home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / ImageWriter--custom dialogs / NewApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-15  |  84.3 KB  |  2,959 lines  |  [TEXT/MPS ]

  1. /*
  2.     copyright © 1991-1994 Apple Computer Inc.  All rights reserved.
  3.     
  4.     NewApp.c
  5.     This file contains all new API implementations for the ImageWriter driver.
  6.     
  7.     Modification history
  8.     03/19/91        TED                New file today
  9.     04/23/91        Sam Weiss        Changed Inherit to Forward
  10.     05/29/91        TED                Added manual feed and faster mode support
  11.     12/20/93        dmh                Sync'd with the shipping 1.0b3 GX driver.
  12.     12/22/93        dmh                Added SD_DespoolPage, which handles image flipping. Marked routines.
  13.      6/14/96        cn                Updated to support Universal Interfaces 2.1.
  14.  
  15. */
  16.  
  17. #include <Memory.h>
  18. #include <QuickDraw.h>
  19. #include <Controls.h>
  20. #include <Errors.h>
  21. #include <ToolUtils.h>
  22. #include <Resources.h>
  23. #include <Packages.h>
  24. #include <GXPrinterDrivers.h>
  25. #include <GXPrinting.h>
  26. #include <FixMath.h>
  27. #include <GXMath.h>
  28. #include <Graphics Routines.h>
  29. #include <GraphicsLibraries.h>
  30. #include <FontLibrary.h>
  31. #include <GXLayout.h>
  32. #include <GXExceptions.h>
  33. #include <PrintingLibraries.h>
  34.  
  35. #include "CommonDefines.h"
  36.  
  37. extern long        A5Size(void);
  38. extern void        A5Init(void *);
  39.  
  40. FourPicts    *gFlippedPicts;        // A pointer holding the PicHandles and flip setting
  41.                                 // for our options dialog.
  42.  
  43.  
  44. /* ------------------------------------------------------------------------------------    */
  45. /*    INTERNAL DEFINES                                                                    */
  46. /* ------------------------------------------------------------------------------------    */    
  47.  
  48. // things this specific driver puts into the DTP config file
  49. #define    kImageWriterConfigType        'ifig'
  50. #define kImageWriterConfigID        (0)            
  51. typedef struct
  52.     {
  53.         Boolean    hasColorRibbon;
  54.         Boolean    hasSheetFeeder;
  55.         Boolean    isImageWriterII;        // is this an ImageWriter II, or an older model?
  56.     } ImageWriterConfigRecord, *ImageWriterConfigPtr, ** ImageWriterConfigHandle;
  57.     
  58. /* Define special characters needed */
  59. #define ESCAPE                (char) 27
  60.  
  61. /* A record to hold a set margins command */
  62. typedef struct SetMarginsRecord
  63.     {
  64.     char        cEscape;                    // ESCAPE character
  65.     char        cCommand;                    // Set Margins command character
  66.     char        cIndentDistance[4];            // number of dots to indent
  67.     } SetMarginsRecord, *SetMarginsPtr;
  68. #define kSetMarginsCommand    (char)'F'        // ImageWriter II uses 'F' for tabbing
  69. #define kSetMarginsSize        6
  70.  
  71. /*     Define a record that can hold one scan line's worth of data, 1280 will
  72.     only happen at 160 dpi. and 14 inch wide paper.   */
  73. typedef struct ScanLineRecord
  74.     {
  75.     char            cColorEscape;                    // ESCAPE character
  76.     char            cSetColorCommand;                // Set color command
  77.     char            cColor;                            // The color
  78.     char            cEscape;                        // ESCAPE character
  79.     char            cCommand;                        // 'enter graphics' command
  80.     char            cLineLength[4];                    // number of dots to print
  81.     char            iTheData[2240];                    // Bits for the data, enough for one line's worth
  82.     } ScanLineRecord, *ScanLinePtr;
  83. #define kGraphicsCommand    (char)'G'        /* graphics printing command */
  84. #define kRepeatGroup        (char)'V'        /* repeat group character */
  85. #define kSetColorCommand     (char)'K'        /* Set color command */
  86. #define kGroupSize            6                /* Size of one group header */
  87.  
  88. #define kScanLineSize         3                /* NOTE: this is just the header size! */
  89.  
  90. #define kStatusCommand        "\033?"            /* request device status/config */
  91.  
  92. // Status flags for PAP status queries
  93. #define    kColorRibbonBit        0
  94. #define kSheetFeederBit        1
  95. #define kPaperOutBit        2
  96. #define kCoverOpenBit        3
  97. #define kOffLineBit            4
  98. #define kPaperJamBit        5
  99. #define kPrinterFaultBit    6
  100. #define kHeadMovingBit        7
  101. #define kPrinterBusyBit        8
  102.  
  103. #define kOutOfPaperMask            (  (0x8000 >> kPaperJamBit) | (0x8000 >> kCoverOpenBit) | (0x8000 >> kOffLineBit) )
  104. #define kPrinterOfflineMask        (  (0x8000 >> kOffLineBit) )
  105. #define kPrinterBusyMask        (  (0x8000 >> kPrinterBusyBit) )
  106.  
  107. //<FF>
  108. /* ------------------------------------------------------------------------------------    */
  109. /*    INTERNAL ROUTINES                                                                */
  110. /* ------------------------------------------------------------------------------------    */
  111. void Long2Dec(long aLong, Ptr emitHere)
  112. /*
  113.     Converts a long into an ASCII string, padded with leading zeros.
  114. */
  115. {    
  116.     char    aString[10];
  117.     short    i, actualWidth, strLength;
  118.     
  119.     NumToString(aLong, (unsigned char *) aString);
  120.     
  121.     // Get the width of the string, check for being too small
  122.     strLength = aString[0];
  123.     actualWidth = strLength;
  124.     if (actualWidth < 4)
  125.         actualWidth = 4;
  126.         
  127.     // output the string, padding with the requested character
  128.     strLength = actualWidth-strLength;
  129.     for (i = 0; i < actualWidth; ++i)
  130.         {
  131.         *emitHere++ = (i < strLength) 
  132.             ? '0' : aString[(i+1)-(strLength)];
  133.         }
  134.         
  135. } // Long2Dec
  136.  
  137.  
  138.  
  139. /*******************************************************************
  140.     SetupFormatPanel sets up our format dialog panel, adding a
  141.     default "flip settings" collection item to the format collection
  142.     if there isn't already one.  This collection item has the values
  143.     we'll use to set up our panel's controls.
  144.     
  145. ********************************************************************/
  146.  
  147. OSErr SetupFormatPanel(short panelResID, gxFormat pageFormat)
  148. {
  149.     OSErr                        err;
  150.     long                        itemSize;
  151.     gxPanelSetupRecord            panelSetupRec;
  152.     gxFlipPageHorizontalInfo    hFlipInfo;
  153.     gxFlipPageVerticalInfo        vFlipInfo;
  154.     FlipCollection                flipSettings;
  155.     short                        oldResFile;
  156.  
  157. // Get the format collection and see if the GX page flip collection
  158. // items are present.  If either is missing, we'll interpret that
  159. // as meaning "don't flip" in that direction.  Store the resulting
  160. // flags in our panel settings structure.
  161.  
  162.     itemSize = sizeof(gxFlipPageHorizontalInfo);
  163.         
  164.     err = GetFmtCollectionItem(&hFlipInfo, &itemSize, gxFlipPageHorizontalTag,
  165.                                gxPrintingTagID, pageFormat);
  166.  
  167.     if (err) hFlipInfo.flipHorizontal = false;
  168.  
  169.     itemSize = sizeof(gxFlipPageVerticalInfo);
  170.     
  171.     err = GetFmtCollectionItem(&vFlipInfo, &itemSize, gxFlipPageVerticalTag,
  172.                                gxPrintingTagID, pageFormat);
  173.  
  174.     if (err)
  175.     {
  176.         vFlipInfo.flipVertical = false;
  177.         err = noErr;
  178.     }
  179.  
  180.     flipSettings.flipHorizontal = hFlipInfo.flipHorizontal;
  181.     flipSettings.flipVertical = vFlipInfo.flipVertical;
  182.     
  183. // Now do the actual panel set up.
  184.  
  185.     panelSetupRec.panelResId        = panelResID;        // Which panel resource?
  186.     panelSetupRec.resourceRefNum    = GXGetMessageHandlerResFile();    // Where is it?
  187.     panelSetupRec.refCon            = 0;                // We don't use this.
  188.     panelSetupRec.panelKind            = gxDriverPanel;    // This is a driver panel.
  189.     
  190.     err = GXSetupDialogPanel(&panelSetupRec);
  191.     nrequire(err, Setup_Failed);
  192.  
  193.     gFlippedPicts = (FourPicts *) NewPtrSysClear(sizeof(FourPicts));
  194.  
  195.  
  196. // Set up the current flipping field in our data structure to reflect
  197. // the type of flipping that's currently set-- 0 = no flipping,
  198. // 1 = horizontal flipping, 2 = vertical flipping, 3 = horizontal and
  199. // vertical flipping.  Based on the current flipping, mark the
  200. // appropriate dialog checkboxes.
  201.  
  202.     gFlippedPicts->curFlipping = hFlipInfo.flipHorizontal +
  203.                                  2 * (char) vFlipInfo.flipVertical;
  204.  
  205.  
  206. // Set up the current flipping field in our data structure to reflect
  207. // the type of flipping.  When done, restore the original resource file
  208. // and exit.
  209.  
  210.     oldResFile = CurResFile();
  211.     UseResFile(GXGetMessageHandlerResFile());
  212.  
  213.     gFlippedPicts->pict[0] = (PicHandle) Get1Resource('PICT', p_Normal);
  214.     nrequire((err = ResError()), CouldNotLoadPict);
  215.     DetachResource((Handle) gFlippedPicts->pict[0]);
  216.     gFlippedPicts->pict[1] = (PicHandle) Get1Resource('PICT', p_HFlip);
  217.     nrequire((err = ResError()), CouldNotLoadPict);
  218.     DetachResource((Handle) gFlippedPicts->pict[1]);
  219.     gFlippedPicts->pict[2] = (PicHandle) Get1Resource('PICT', p_VFlip);
  220.     nrequire((err = ResError()), CouldNotLoadPict);
  221.     DetachResource((Handle) gFlippedPicts->pict[2]);
  222.     gFlippedPicts->pict[3] = (PicHandle) Get1Resource('PICT', p_HVFlip);
  223.     nrequire((err = ResError()), CouldNotLoadPict);
  224.     DetachResource((Handle) gFlippedPicts->pict[3]);
  225.  
  226. CouldNotLoadPict:
  227.     UseResFile(oldResFile);
  228.  
  229. Setup_Failed:
  230.  
  231.     return err;
  232. }
  233.  
  234.  
  235. void TearDownFormatPanel(gxDialogResult    theResult, gxFormat pageFormat)
  236. {
  237.     char    idx;
  238.     
  239.     if (theResult == gxOKSelected)
  240.         SetFormatFlipping(gFlippedPicts->curFlipping, pageFormat);
  241.         
  242.     for (idx = 0; idx < 4; idx++)
  243.         if (gFlippedPicts->pict[idx])
  244.             DisposHandle((Handle) gFlippedPicts->pict[idx]);
  245. }
  246.  
  247.  
  248. //<FF>
  249. /* ------------------------------------------------------------------------------------    */
  250. Boolean PrinterHasColorRibbon(gxPrinter thePrinter)
  251. /*
  252.     Returns true if the config file says that the printer is blessed with a color ribbon,
  253.     false if it is a black and white ribbon.
  254. */
  255. {
  256.     Boolean                        hasColor = true;
  257.     Str32                        deviceName;
  258.     OSErr                        anErr;
  259.     ImageWriterConfigHandle        configHandle;
  260.     
  261.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  262.     GXGetPrinterName(thePrinter, deviceName);
  263.     if (deviceName[0] != 0)
  264.         {
  265.         // if we are going to a particular device, assume no color, as that is more common
  266.         hasColor = false;
  267.         
  268.         anErr = GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, &(Handle)configHandle);
  269.         if (anErr == noErr)
  270.             {
  271.             hasColor = (**configHandle).hasColorRibbon;
  272.             DisposHandle((Handle) configHandle);
  273.             }
  274.         }
  275.     
  276.     return(hasColor);
  277.     
  278. } // PrinterHasColorRibbon
  279.  
  280.  
  281. //<FF>
  282. /* ------------------------------------------------------------------------------------    */
  283. gxViewDevice    NewDeviceResolutionViewDevice(void)
  284. /*
  285.     This routine creates a viewDevice and gives it a scale factor in it's mapping
  286.     appropriate for this device (144 dpi in the case of the IW)
  287. */
  288. {
  289.     gxViewDevice        vd;
  290.     
  291.     // create the viewDevices with a fake bitmap
  292.     {
  293.     gxShape        tempBitmap;
  294.     gxBitmap        aBitmap;
  295.     
  296.     aBitmap.pixelSize     = 1;
  297.     aBitmap.rowBytes     = 0;
  298.     aBitmap.width         = 0;
  299.     aBitmap.height         = 0;
  300.     aBitmap.image         = (char*)gxMissingImagePointer;
  301.     aBitmap.space         = gxNoSpace;
  302.     aBitmap.set         = nil;
  303.     aBitmap.profile     = nil;
  304.     
  305.     tempBitmap = GXNewBitmap(&aBitmap, nil);
  306.     vd = GXNewViewDevice(gxScreenViewDevices, tempBitmap);
  307.     GXDisposeShape(tempBitmap);
  308.     }
  309.  
  310.     // setup a mapping for a 144 (2X) viewDevice
  311.     {
  312.     gxMapping    vdMapping;
  313.     
  314.     ResetMapping(&vdMapping);
  315.     ScaleMapping(&vdMapping, ff(2), ff(2), ff(0), ff(0));
  316.     
  317.     GXSetViewDeviceMapping(vd, &vdMapping);
  318.     }
  319.     
  320.     return(vd);
  321.     
  322. } // NewDeviceResolutionViewDevice
  323.  
  324. //<FF>
  325. /* ------------------------------------------------------------------------------------    */
  326. Boolean    JobIsBest(long *imagewriterOptions)
  327. /*
  328.     Returns true if the current job is a final quality mode job, else returns false.
  329.     Also, returns the imagewriter rendering options.
  330. */
  331. {
  332.     Boolean            isFinal;
  333.     gxQualityInfo    jobQualitySettings;
  334.     long            itemSize = sizeof(jobQualitySettings);
  335.     OSErr            status;
  336.     Collection        jobCollection;
  337.     
  338.     // cache the collection
  339.     jobCollection = GXGetJobCollection(GXGetJob());
  340.     
  341.     // find out the info
  342.         
  343.     isFinal = false;
  344.     
  345.     status = GetCollectionItem(jobCollection, 
  346.                                     gxQualityTag, gxPrintingTagID, 
  347.                                     &itemSize, &jobQualitySettings);
  348.     
  349.     if ( (status == noErr) && (jobQualitySettings.currentQuality == (jobQualitySettings.qualityCount-1)) )
  350.         isFinal = true;
  351.     
  352.     ncheck( status );
  353.  
  354.     // we default to super res
  355.     *imagewriterOptions = kSuperRes;
  356.     itemSize = sizeof(imagewriterOptions);
  357.     status = GetCollectionItem(jobCollection, 
  358.                                     DriverCreator, 0, 
  359.                                     &itemSize, imagewriterOptions);
  360.                 
  361.     // and return the job quality mode
  362.     return(isFinal);
  363.     
  364. } // JobIsBest
  365.  
  366.  
  367. //<FF>
  368. /* ------------------------------------------------------------------------------------    */
  369.  
  370. OSErr    DoTheQuery(unsigned short * statusReturn, Boolean papStatus)
  371. /*
  372.     Returns in statusString the current status for the printer.  Returns various
  373.     errors from IO package if the printer's status could not be found.
  374. */
  375. {
  376.     OSErr                anErr = noErr;
  377.     long                statusLength;                    // status string size
  378.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  379.  
  380.     // default to a clear status
  381.     *statusReturn = 0;
  382.  
  383.     // send the query
  384.     if (papStatus)
  385.         {
  386.         char    statusString[255];                // returned string
  387.         
  388.         // According to the old IW driver, sometimes it will return all of the bits
  389.         // set.  This is an error, but we can just try again.
  390.         do {
  391.             statusLength = 255;
  392.             anErr = Send_GXGetDeviceStatus(nil, 0, statusString, &statusLength, nil);
  393.             } while ( (anErr == noErr) && (statusString[0] == 0xFF) );
  394.         
  395.         // return the printer status bits in the PAP case
  396.         *statusReturn = *(unsigned short*)&statusString[0];
  397.         }
  398.     else
  399.         {
  400.         char    statusString[8];                // returned string
  401.  
  402.         if ((**hGlobals).isImageWriterII)
  403.             {
  404.             statusLength = 8; // max number of characters to get back
  405.             anErr = Send_GXGetDeviceStatus(kStatusCommand, 2, statusString, &statusLength, "\p\n");
  406.                 
  407.             if ( anErr == gxAioTimeout)
  408.                 {
  409.                 *statusReturn = kPrinterOfflineMask;
  410.                 anErr = noErr;
  411.                 }
  412.             else
  413.                 {
  414.                 if (anErr == noErr)
  415.                     {
  416.                     // generate printer status bits in the serial case
  417.                     if (statusString[4] == 'C')
  418.                         *statusReturn |= 0x8000 >> kColorRibbonBit;
  419.                     if ( (statusString[5] == 'F') || (statusString[4] == 'F') )
  420.                         *statusReturn |= 0x8000 >> kSheetFeederBit;
  421.                     }
  422.                 }
  423.             }
  424.         }
  425.         
  426.     nrequire(anErr, Send_GXGetDeviceStatus);
  427.  
  428. // FALL THROUGH EXCEPTION HANDLING    
  429. Send_GXGetDeviceStatus:
  430.     
  431.     return(anErr);
  432.  
  433. } // DoTheQuery
  434.  
  435. //<FF>
  436. /* ------------------------------------------------------------------------------------    */
  437. OSErr FetchStatusString(unsigned short * statusReturn, Boolean papStatus, Boolean doRetry)
  438. /*
  439.     Returns in statusString the current status for the printer.  Returns various
  440.     errors from IO package if the printer's status could not be found.
  441.     
  442.     Handles reporting error conditions to the user.
  443. */
  444. {
  445.     OSErr            anErr;
  446.     
  447.     anErr = DoTheQuery(statusReturn, papStatus);        
  448.     nrequire(anErr, Send_GXGetDeviceStatus);
  449.     
  450.     // printer offline?
  451.     if (     
  452.         ( ((*statusReturn) & kPrinterOfflineMask) != 0 )  
  453.         )
  454.         {
  455.         gxStatusRecord        theStat, *pStat = &theStat;
  456.         Boolean                printerIsFixed = false;
  457.         
  458.         pStat->statResId     = kDriverStatus;        
  459.         pStat->statResIndex = kCheckOnline;            
  460.         pStat->bufferLen      = 0;
  461.         pStat->dialogResult = 0;
  462.         
  463.  
  464.         // keep sending the user the alert until either
  465.         //  a) the problem resolves itself
  466.         //  b) the user responds via the dialog
  467.         //  c) some other (fatal) error happens
  468.         do
  469.             {
  470.             
  471.             // tell the user
  472.             anErr = GXAlertTheUser(pStat);
  473.             
  474.             // if printer got suddenly turned online, do an OK
  475.             if (doRetry)
  476.                 {
  477.                 (void) DoTheQuery(statusReturn, papStatus);        
  478.                 if (     
  479.                     ( ((*statusReturn) & kPrinterOfflineMask) == 0 ) 
  480.                     )
  481.                     {
  482.                     printerIsFixed = true;
  483.                     pStat->dialogResult = ok;
  484.                     anErr = noErr;
  485.                     }
  486.                 }
  487.                 
  488.             } while ((anErr == noErr) && (pStat->dialogResult == 0));
  489.  
  490.         // based on the user's response, continue or cancel
  491.         if (printerIsFixed)
  492.             anErr = noErr;
  493.         else
  494.             anErr = gxPrUserAbortErr;
  495.         
  496.         // display "sending data to the printer" message
  497.         if (anErr == noErr)
  498.             anErr = GXReportStatus(kDriverStatus, kSendingData);
  499.         }
  500.  
  501. // FALL THROUGH EXCEPTION HANDLING    
  502. Send_GXGetDeviceStatus:
  503.     
  504.     return(anErr);
  505.     
  506. } // FetchStatusString
  507.  
  508. //<FF>
  509. /* ------------------------------------------------------------------------------------    */
  510. OSErr UpdateConfiguration(void)
  511. /*
  512.     This routine queries the printer for its hardware configuration (color ribbon and
  513.     sheet feeder options), and stores that info into the configuration file.
  514. */
  515. {
  516.     SpecGlobalsHdl                 hGlobals = GetMessageHandlerInstanceContext();
  517.     Str32                        deviceName;
  518.     OSErr                        anErr = noErr;
  519.     ImageWriterConfigHandle        configHandle;
  520.     ImageWriterConfigPtr        configPtr;
  521.     Boolean                        isImageWriterII = false;
  522.     ResType                        commType;
  523.     
  524.         
  525.     // find out what we are printing to, and how we are connected
  526.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  527.     anErr = GXFetchDTPData(deviceName, gxDeviceCommunicationsType, gxDeviceCommunicationsID, (Handle*)&configHandle);
  528.     nrequire(anErr, FetchCommType);
  529.     commType = **(ResType**)configHandle;
  530.     DisposHandle((Handle) configHandle);
  531.     
  532.     
  533.     // store away the communications type for future use
  534.     {
  535.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  536.     
  537.     (**hGlobals).commType = commType;
  538.     }
  539.     
  540.     // find out the original configuration
  541.     if (GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle*)&configHandle) == noErr)
  542.         {
  543.         // remember if we thought we had an IW2 when we started
  544.         configPtr = *configHandle;
  545.         (**hGlobals).isImageWriterII = isImageWriterII = configPtr->isImageWriterII;
  546.         DisposeHandle((Handle) configHandle);
  547.  
  548.         // if we aren't an ImageWriter II, bail out now - because the timeout takes two minutes!
  549.         if (!isImageWriterII)
  550.             return(noErr);            
  551.         }
  552.     else
  553.         {        
  554.         // if we don't know yet, assume IW2 for PAP else Serial
  555.         if (commType == 'PPTL')
  556.             isImageWriterII = true;
  557.             
  558.         // Assume IW 2 so we do the query for real
  559.         (**hGlobals).isImageWriterII = true;
  560.         }
  561.         
  562.     // make a handle to hold our configuration information for the printer
  563.     configHandle = (ImageWriterConfigHandle) NewHandle(sizeof(ImageWriterConfigRecord) );
  564.     anErr = MemError();
  565.     nrequire(anErr, NewHandle);
  566.     
  567.     // setup the default for the device - in case the query fails
  568.     configPtr = *configHandle;
  569.     configPtr->hasColorRibbon = false;
  570.     configPtr->hasSheetFeeder = false;
  571.     configPtr->isImageWriterII = true;
  572.     
  573.     {
  574.     unsigned short    statusReturn;
  575.     
  576.     // query the device
  577.     anErr = FetchStatusString(&statusReturn, (commType == 'PPTL'), isImageWriterII);
  578.     
  579.     // and scan the string looking for information about printer kind and options
  580.     configPtr = *configHandle;
  581.     if ( anErr == gxAioTimeout )
  582.         {
  583.         // if we timeout and we don't know the printer kind - assume IW1
  584.         if (!isImageWriterII)
  585.             {
  586.             anErr = noErr;
  587.             isImageWriterII = configPtr->isImageWriterII = false;
  588.             }
  589.         }
  590.     else
  591.         {
  592.         isImageWriterII = true;
  593.         configPtr->hasColorRibbon = (statusReturn & (0x8000 >> kColorRibbonBit)) != 0;
  594.         configPtr->hasSheetFeeder = (statusReturn & (0x8000 >> kSheetFeederBit)) != 0;
  595.         }
  596.     nrequire(anErr, FetchStatusString);
  597.     }
  598.     
  599.     // Remember if this was an ImageWriter II after the query
  600.     (**hGlobals).isImageWriterII = isImageWriterII;
  601.     
  602.     // write out the new configuration
  603.     anErr = GXWriteDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle)configHandle);
  604.     
  605.     
  606. // CLEANUP EXCEPTION HANDLING
  607. FetchStatusString:
  608.     DisposHandle((Handle) configHandle);
  609.     
  610. NewHandle:
  611. FetchCommType:
  612.     return(anErr);
  613.     
  614. } // UpdateConfiguration
  615.  
  616.  
  617. /* ------------------------------------------------------------------------------------    */
  618. OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
  619. /*
  620.     This routine writes out a single character in the native set of the printer.
  621.     It uses a table that's part of the driver to do the right thing in order to generate this
  622.     character.
  623. */
  624. {
  625.     OSErr        anErr = noErr;
  626.     char        outputChars[20];                // a maximum of 20 characters can be generated
  627.     short        charCount;                    
  628.     
  629.     // For each character in the buffer, determine how to map the character to a draft character
  630.     for (; numChars > 0; --numChars, ++draftChar)
  631.     {
  632.         // No characters yet for this output character
  633.         charCount = 0;
  634.             
  635.         // Only consider characters in the printable range
  636.         if (*draftChar >= 0x20)
  637.         {
  638.             unsigned long    draftControl = (*draftTable)[*draftChar-0x20];    // Fetch native mode long word corresponding to this character
  639.             unsigned char    outChar;
  640.             unsigned char    nationalSet;
  641.             short                i;
  642.             
  643.             // For each word which composes the native mode long word 
  644.             for (i = 1; i >= 0; --i)
  645.             {
  646.                 // Should we send a backspace character (to overstrike)?
  647.                 if ( (draftControl & 0x80000000) != 0 )
  648.                     outputChars[charCount++] = 0x08;
  649.                 
  650.                 outChar = (draftControl >> 16) & 0xFF;
  651.                 if (outChar != 0)
  652.                 {
  653.                     // Determine the national character set to select
  654.                     nationalSet = (draftControl >> 24) & 0xF;    
  655.     
  656.                     //    Is this character in the standard, built-in character set?
  657.                     if (nationalSet == 0)
  658.                     {
  659.                         outputChars[charCount++] = outChar;
  660.                     }
  661.                     else    //    T => Must select a foreign language character set 
  662.                     {
  663.                         outputChars[charCount++] = 0x1B;
  664.                         outputChars[charCount++] = 0x44;
  665.                         outputChars[charCount++] = nationalSet;
  666.                         outputChars[charCount++] = 0x00;
  667.                         outputChars[charCount++] = outChar;
  668.                         outputChars[charCount++] = 0x1B;                // We always switch back to the kAmerican character set
  669.                         outputChars[charCount++] = 0x5A;
  670.                         outputChars[charCount++] = 0x07;
  671.                         outputChars[charCount++] = 0x00;
  672.                     }
  673.                 }
  674.                 
  675.                 // Take the next (low) word and process it (if we're not all done)
  676.                 draftControl <<= 16;
  677.             }    
  678.         }
  679.             
  680.         // If we generated any data, send it out now
  681.         if (charCount > 0)
  682.             anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
  683.     }
  684.         
  685.     return(anErr);    
  686.     
  687. } // WriteDraftChars
  688.  
  689. /* ------------------------------------------------------------------------------------    */
  690. OSErr GetPointerThisBig(Ptr *theBuff, long numBytes) 
  691. {
  692.     OSErr        anErr = noErr;
  693.     
  694.     if (*theBuff != nil)
  695.     {
  696.         if ( GetPtrSize(*theBuff) < numBytes )    //    T => Won't be big enough; make a new one
  697.         {
  698.             DisposPtr(*theBuff);
  699.             *theBuff = nil;
  700.         }
  701.     }
  702.  
  703.     if (*theBuff == nil)
  704.     {
  705.         *theBuff = NewPtrClear(numBytes);
  706.         anErr = MemError();
  707.     }
  708.     
  709.     return(anErr);
  710.     
  711. } // GetPointerThisBig
  712.  
  713. /* ------------------------------------------------------------------------------------    */
  714. OSErr GetTextAndPosition(    gxShape            theShape, 
  715.                             Ptr                *theChars, 
  716.                             long            *numChars, 
  717.                             gxPoint            *textPosition)
  718. {
  719.     OSErr        anErr = noErr;
  720.     long        textLength;
  721.     
  722.     // Determine the size of the text data and the position of the text
  723.     textLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
  724.  
  725.     // Make sure we have a buffer pointer large enough to hold all of the data
  726.     
  727.     anErr = GetPointerThisBig(theChars, textLength);
  728.     require(anErr == noErr, CantAllocTextBuff);
  729.     
  730.     // Now we retrieve the text
  731.     GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
  732.     
  733.     // Remember the number of characters in the shape
  734.     *numChars = textLength;
  735.     
  736.  
  737. /******* Clean-up *******/
  738.  
  739. CantAllocTextBuff:
  740.     return(anErr);
  741.     
  742. } // GetTextAndPosition
  743.  
  744. /* ------------------------------------------------------------------------------------    */
  745. OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
  746. {
  747.     OSErr                    anErr = noErr;
  748.     long                    i;
  749.     long                    numItems;
  750.     Fixed                    currYPos = ff(0);
  751.     Ptr                        theChars = nil;
  752.     long                    numChars = 0;
  753.     gxPoint                    textPosition;
  754.     Fixed                    oldTextSize = ff(0);
  755.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  756.     
  757.     // Since the page picture we need to process is a picture shape that's embedded in
  758.     // thePage (a shape containing one item => a picture), we need to extract the real
  759.     // page picture from thePage.
  760.     
  761.     thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
  762.     numItems = GXGetPicture(thePage, nil, nil, nil, nil);
  763.     
  764.     // For each shape within the picture, check its type and process it accordingly
  765.     
  766.     for (i = 1; i <= numItems; ++i)
  767.     {
  768.         gxShape                theShape;
  769.         short                theType;
  770.                 
  771.         theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
  772.         theType = GXGetShapeType(theShape);
  773.         
  774.         if (theType == gxLayoutType)    //    T => We have a layout shape
  775.         {
  776.             Fixed        textSize;
  777.             char        buff[12];
  778.             char        theFace;
  779.             short        cmndBuffSz;
  780.             
  781.             // First determine the style in which we're printing
  782.             
  783.             theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
  784.             
  785.             buff[0] = ESCAPE;
  786.             if ( (theFace & bold) != 0 )    //    T => Turn bold facing on
  787.                 buff[1] = '!';
  788.             else                                    //    T => Turn it off
  789.                 buff[1] = '"';
  790.             
  791.             buff[2] = ESCAPE;
  792.             if ( (theFace & underline) != 0 )    //    T => Turn underline facing on
  793.                 buff[3] = 'X';
  794.             else                                            //    T => Turn it off
  795.                 buff[3] = 'Y';
  796.                 
  797.             cmndBuffSz = 4;
  798.             
  799.             // Next determine if we need to change the size of the font being used
  800.             
  801.             textSize = GXGetShapeTextSize(theShape);
  802.             if (textSize != oldTextSize)    //    T => Must issue LQ command to change font size
  803.             {
  804.                 buff[4] = ESCAPE;                //    The first escape command selects black color
  805.                 buff[5] = kSetColorCommand;
  806.                 buff[6] = '0';
  807.                 
  808.                 buff[7] = ESCAPE;                //    The second escape command selects a draft font
  809.                 buff[8] = 'a';
  810.                 buff[9] = '1';
  811.                 
  812.                 buff[10] = ESCAPE;                //    The third escape command selects the character pitch
  813.                 
  814.                 if ( textSize <= ff(10) )    //    T => Select 10 cpi
  815.                 {
  816.                     buff[11] = 'N';
  817.                 }
  818.                 else    //    T => All other sizes get mapped to 12 cpi
  819.                 {
  820.                     buff[11] = 'E';
  821.                 }
  822.                 
  823.                 // Remember the last text size
  824.                 oldTextSize = textSize;    
  825.                 
  826.                 // Adjust the size of the data to be sent to the printer
  827.                 cmndBuffSz += 8;
  828.             }
  829.             // else - no change in font size
  830.             
  831.             // Send the commands to the printer
  832.             anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
  833.             require(anErr == noErr, CantSendFontCmnd);
  834.  
  835.             // Get the ASCII text and the starting position of the data
  836.             anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
  837.             require(anErr == noErr, CantGetTextAndPos);
  838.             
  839.             if ( (currYPos != ff(0)) && (currYPos != textPosition.y) )    //    T => Moving to a lower line, finish the last ;line with a CR
  840.             {
  841.                 char        c = 0x0D;
  842.                 
  843.                 anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  844.                 require(anErr == noErr, CantSendCRCmnd);
  845.             }
  846.             
  847.             // Position the print head to the proper location on the page
  848.             {
  849.                 gxMapping                theMapping;
  850.                 long                    lineFeedSize;
  851.                 Str255                    positionCmndsBuff;
  852.                 unsigned long            bytesInBuff = 0;
  853.                 char                    *p;
  854.  
  855.                 GXGetShapeMapping(theShape, &theMapping);
  856.                 MapPoints(&theMapping, (long) 1, &textPosition);    //    Just map the first point
  857.                 
  858.                 // Now position the print head vertically
  859.  
  860.                 lineFeedSize = (textPosition.y - currYPos) >> 16;
  861.                 anErr = Send_GXRasterLineFeed(&lineFeedSize, (char *) positionCmndsBuff, &bytesInBuff, imageData);
  862.                 require(anErr == noErr, CantEmitLineFeeds);
  863.                 
  864.                 // Update the current Y position pointer on the page
  865.                 currYPos = textPosition.y;
  866.  
  867.                 // Now position the print head horizontally on the page
  868.  
  869.                 p = (char *) &positionCmndsBuff[bytesInBuff];        
  870.                 *p++ = ESCAPE;
  871.                 *p++ = 'F';
  872.                 Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p);    // Convert left margin into ASCII and place it at the start of the scan line
  873.                 
  874.                 // Update the number of bytes in the buffer
  875.                 bytesInBuff += 6;
  876.  
  877.                 // Send the positioning info to the printer
  878.                 anErr = Send_GXBufferData((char *) positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
  879.                 require(anErr == noErr, CantSendPositionCmnds);
  880.             }
  881.             
  882.             // Now we send the text data to the printer
  883.             anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, (unsigned char *) theChars, numChars);
  884.             require(anErr == noErr, CantWriteChars);
  885.         }
  886.     }    // for
  887.  
  888.     // Send one last CR to wrap the last line (if there was one)
  889.     {
  890.         char        c = 0x0D;
  891.         
  892.         anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  893.     }
  894.  
  895.  
  896. /******* Clean-up *******/
  897.  
  898. CantWriteChars:
  899. CantSendPositionCmnds:
  900. CantEmitLineFeeds:
  901. CantSendCRCmnd:
  902. CantGetTextAndPos:
  903. CantSendFontCmnd:
  904.     if (theChars != nil)
  905.         DisposPtr(theChars);
  906.                 
  907.     return(anErr);
  908.     
  909. } // PrintPageInDraftMode 
  910.  
  911. //<FF>
  912. /* ------------------------------------------------------------------------------------    */
  913. /*    SPECIFIC DRIVER UNIVERSAL OVERRIDES                                                    */
  914. /* ------------------------------------------------------------------------------------    */
  915. OSErr SD_Initialize (void) 
  916. /*
  917.     The SD_Initalize message is called when a new job is created.  The standard
  918.     thing to do is to allocate and fill out your globals as you see fit.
  919. */
  920. {
  921.  
  922.     SpecGlobalsHdl     hGlobals;
  923.     OSErr             anErr;
  924.         
  925.     // we make our globals
  926.     hGlobals = (SpecGlobalsHdl) NewHandleClear( sizeof(SpecGlobals) );
  927.     anErr = MemError();
  928.  
  929.     // and we save them away
  930.     SetMessageHandlerInstanceContext(hGlobals);
  931.  
  932.     // is everything okay?
  933.     nrequire(anErr, MNewHandleClear);
  934.     
  935.     // Don't need to initialize because of the NewHandleCLEAR
  936.     //(**hGlobals).draftTable = nil;
  937.     //(**hGlobals).lineFeeds = 0;
  938.     //(**hGlobals).packagingOptions = kNoPackagingOptions;
  939.     
  940.     return(noErr);
  941.     
  942.     
  943. /*-----EXCEPTION HANDLING------*/
  944.  
  945.  
  946. MNewHandleClear:
  947.     return(anErr);
  948.     
  949. } // SD_Initialize
  950.  
  951.  
  952. //<FF>
  953. /* ------------------------------------------------------------------------------------    */
  954. OSErr SD_ShutDown(void) 
  955. /*
  956.     Shutdown is called when the job is done with.  A good thing to do is to get
  957.     rid of any additional storage that is laying around.
  958. */
  959. {
  960.     // clean up our stuff
  961.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  962.  
  963.     // get rid of the draft table (if we have one);
  964.     DisposHandle((**hGlobals).draftTable);
  965.     
  966.     // we get rid of our storage
  967.     DisposHandle((Handle) hGlobals);
  968.     
  969.     // clear out our globals - to avoid double disposes
  970.     SetMessageHandlerInstanceContext(nil);
  971.  
  972.     return(noErr);
  973.     
  974.     
  975. } // SD_ShutDown
  976.  
  977. //<FF>
  978. /* ------------------------------------------------------------------------------------    */
  979. OSErr    SD_DefaultPrinter(gxPrinter thePrinter)
  980. /*
  981.     This call is made to setup the default printer object.  The job of the
  982.     specific driver is to add in any viewDevices that it wishes applications
  983.     to be able to format specifically for.
  984. */
  985. {
  986.     OSErr            anErr;
  987.     gxViewDevice    vd;
  988.     gxJob            theJob = GXGetJob();
  989.     
  990.     // add the standard viewDevices first
  991.     anErr = Forward_GXDefaultPrinter(thePrinter);
  992.     nrequire(anErr, DefaultPrinter);
  993.     
  994.     // add a 144 b/w viewDevice
  995.     vd = NewDeviceResolutionViewDevice();
  996.     {
  997.     gxSetColor        theColors[2];
  998.     gxSetColor        *pColor;
  999.     gxColorSet        theSet;
  1000.     
  1001.     pColor = &theColors[0];
  1002.     
  1003.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;
  1004.     
  1005.     pColor++;
  1006.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
  1007.     
  1008.     theSet = GXNewColorSet(gxRGBSpace, 2, theColors);
  1009.     SetViewDeviceColorSet(vd, theSet);
  1010.     GXDisposeColorSet(theSet);
  1011.     }
  1012.         
  1013.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  1014.     nrequire(anErr, FailedAddBWViewDevice);
  1015.  
  1016.     
  1017.     // add a 144 color viewDevice with 8 colors in it
  1018.     //
  1019.     //    Color        Index        R            G            B
  1020.     //    white        0            0xFFFF        0xFFFF        0xFFFF        
  1021.     //    yellow        1            0xFFFF        0xFFFF        0x0000
  1022.     //    magenta        2            0xFFFF        0x0000        0xFFFF
  1023.     //    red            3            0xFFFF        0x0000        0x0000
  1024.     //    cyan        4            0x0000        0xFFFF        0xFFFF
  1025.     //    green        5            0x0000        0xFFFF        0x0000
  1026.     //    blue        6            0x0000        0x0000        0xFFFF
  1027.     //    black        7            0x0000        0x0000        0x0000
  1028.     
  1029.     if (PrinterHasColorRibbon(thePrinter))
  1030.         {
  1031.         gxSetColor        theColors[8];
  1032.         gxSetColor        *pColor;
  1033.         gxColorSet        theSet;
  1034.         short            idx;
  1035.  
  1036.         vd = NewDeviceResolutionViewDevice();
  1037.         
  1038.         pColor = &theColors[0];
  1039.         for (idx = 0; idx < 8; ++idx)
  1040.             {
  1041.             // default the color to black
  1042.             pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
  1043.             
  1044.             // and give it componants to go along with this index
  1045.             if (idx & 0x04)
  1046.                 pColor->rgb.red     = 0xFFFF;
  1047.             if (idx & 0x02)
  1048.                 pColor->rgb.green     = 0xFFFF;
  1049.             if (idx & 0x01)
  1050.                 pColor->rgb.blue     = 0xFFFF;
  1051.                 
  1052.             // move on to the next color
  1053.             ++pColor;
  1054.             }
  1055.         
  1056.         theSet = GXNewColorSet(gxRGBSpace, 8, theColors);
  1057.         SetViewDeviceColorSet(vd, theSet);
  1058.         GXDisposeColorSet(theSet);
  1059.  
  1060.         anErr = GXAddPrinterViewDevice(thePrinter, vd);
  1061.         nrequire(anErr, FailedAddColorViewDevice);
  1062.         }
  1063.     
  1064.     /* Only if we are the output printer (not the formatting printer) */
  1065.     if (GXGetJobPrinter(theJob) == GXGetJobOutputPrinter(theJob)) {
  1066.         Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1067.         Handle                 jobQualitySettingsHdl;    
  1068.         gxQualityInfo        *qualitySettings;
  1069.         Ptr                    p;
  1070.         Str255                bestString, roughString;
  1071.  
  1072.         // read in our quality mode strings
  1073.         {
  1074.         short    curResFile = CurResFile();
  1075.         
  1076.         UseResFile(GXGetMessageHandlerResFile());
  1077.         
  1078.         GetIndString( bestString, kNewQualityID, kBestString);
  1079.         GetIndString( roughString, kNewQualityID, kRoughString);
  1080.         UseResFile(curResFile);
  1081.         }
  1082.         
  1083.         jobQualitySettingsHdl = NewHandle(0);
  1084.         anErr = MemError();
  1085.         nrequire(anErr, FailedNewHandle);
  1086.  
  1087.         anErr = GetCollectionItemHdl (     jobCollection,
  1088.                                         gxQualityTag,
  1089.                                         gxPrintingTagID,
  1090.                                         jobQualitySettingsHdl );
  1091.  
  1092.         if (anErr == noErr) 
  1093.             {    /* Check for proper structure -- count as not found if different */
  1094.             HLockHi(jobQualitySettingsHdl);
  1095.  
  1096.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1097.             p = qualitySettings->qualityNames;
  1098.  
  1099.             if (qualitySettings->disableQuality) 
  1100.                 anErr = collectionItemNotFoundErr;
  1101.             else if (qualitySettings->qualityCount != 2)
  1102.                 anErr = collectionItemNotFoundErr;
  1103.             else if (! IUEqualString((unsigned char const *) p, bestString))
  1104.                 anErr = collectionItemNotFoundErr;
  1105.             else if (! IUEqualString((unsigned char const *) (p + p[0] + 1), roughString))
  1106.                 anErr = collectionItemNotFoundErr;
  1107.  
  1108.             HUnlock(jobQualitySettingsHdl);
  1109.             }
  1110.  
  1111.         if (anErr == collectionItemNotFoundErr) 
  1112.             {
  1113.             Size            count;
  1114.  
  1115.             /* Create the proper quality item */
  1116.             SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
  1117.             anErr = MemError();
  1118.             nrequire( anErr, FailedSetHandleSize );
  1119.                 
  1120.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1121.             
  1122.             qualitySettings->disableQuality = false;
  1123.             qualitySettings->defaultQuality = 1;
  1124.             qualitySettings->currentQuality = 1;
  1125.             qualitySettings->qualityCount = 2;
  1126.  
  1127.             count = bestString[0]+1;
  1128.             p = qualitySettings->qualityNames;
  1129.             BlockMove( bestString, p, count );
  1130.  
  1131.             p += count;
  1132.             BlockMove( roughString, p, roughString[0]+1 );
  1133.  
  1134.             /* Add the proper quality item */
  1135.             anErr = AddCollectionItemHdl (     jobCollection,
  1136.                                             gxQualityTag,
  1137.                                             gxPrintingTagID,
  1138.                                             jobQualitySettingsHdl );
  1139.  
  1140.             /* Make it vilatile by driver */
  1141.             if (anErr == noErr)
  1142.                 (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
  1143.  
  1144.             }
  1145.         
  1146. FailedSetHandleSize:
  1147.         DisposHandle(jobQualitySettingsHdl);
  1148.     }
  1149. FailedNewHandle:
  1150.     
  1151.     ncheck(noErr);
  1152.     return(noErr);
  1153.     
  1154.     
  1155.     
  1156. // EXCEPTION HANDLING
  1157. FailedAddColorViewDevice:
  1158. FailedAddBWViewDevice:
  1159.     GXDisposeViewDevice(vd);
  1160.     
  1161. DefaultPrinter:
  1162.     return(anErr);
  1163.     
  1164. } // SD_DefaultPrinter
  1165.  
  1166. //<FF>
  1167. /* ------------------------------------------------------------------------------------    */
  1168.  
  1169. OSErr SD_DefaultFormat(gxFormat theFormat)
  1170. {
  1171.     OSErr                anErr;
  1172.     Handle                 jobQualitySettingsHdl;    
  1173.     
  1174.     anErr = Forward_GXDefaultFormat(theFormat);
  1175.     
  1176.     // now, if the application has set up a special formatting mode, we need to update
  1177.     // the quality mode collection item (and any private ones we use)
  1178.     if (anErr == noErr)
  1179.         {
  1180.         gxPoint                dpiPoint;
  1181.         gxMapping            vdMapping;
  1182.         gxViewDevice        selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
  1183.         
  1184.         
  1185.         dpiPoint.x = ff(72);
  1186.         dpiPoint.y = ff(72);
  1187.         
  1188.         if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
  1189.             {
  1190.             GXGetViewDeviceMapping(selectedDevice, &vdMapping);
  1191.             MapPoints(&vdMapping, 1, &dpiPoint);
  1192.             
  1193.             {
  1194.             Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1195.             gxQualityInfo        *qualitySettings;
  1196.     
  1197.             jobQualitySettingsHdl = NewHandle(0);
  1198.             anErr = MemError();
  1199.             nrequire(anErr, FailedNewHandle);
  1200.  
  1201.             anErr = GetCollectionItemHdl (     jobCollection,
  1202.                                                 gxQualityTag,
  1203.                                                  gxPrintingTagID,
  1204.                                                jobQualitySettingsHdl );
  1205.  
  1206.             nrequire(anErr, FailedGetCollectionItemHdl);
  1207.  
  1208.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1209.  
  1210.             qualitySettings->currentQuality = 
  1211.                 (dpiPoint.y > ff(100)) ? (qualitySettings->qualityCount-1) : 0;
  1212.  
  1213.             anErr = AddCollectionItemHdl (     jobCollection,
  1214.                                             gxQualityTag,
  1215.                                             gxPrintingTagID,
  1216.                                             jobQualitySettingsHdl );
  1217.                                                  
  1218.             DisposHandle(jobQualitySettingsHdl);
  1219.             }
  1220.  
  1221.         
  1222.             if (anErr == noErr)
  1223.                 {
  1224.                 long    formatOptions;
  1225.                 
  1226.                 // turn off super-res
  1227.                 formatOptions = 0;
  1228.                 anErr = AddCollectionItem(GXGetFormatCollection(theFormat), 
  1229.                     DriverCreator, 0,
  1230.                     sizeof(formatOptions),
  1231.                     &formatOptions);
  1232.                 }
  1233.             }
  1234.         }
  1235.  
  1236. FailedNewHandle:        
  1237.     ncheck(anErr);
  1238.     return(anErr);
  1239.  
  1240. FailedGetCollectionItemHdl:
  1241.     DisposHandle(jobQualitySettingsHdl);
  1242.     return(anErr);
  1243.     
  1244. } // SD_DefaultFormat
  1245.  
  1246. //<FF>
  1247. /* ------------------------------------------------------------------------------------    */
  1248. OSErr SD_DefaultJob()
  1249. /*
  1250.     We override this message to add our default - highest res possible
  1251. */
  1252. {
  1253.     OSErr    anErr;
  1254.     
  1255.     anErr = Forward_GXDefaultJob();
  1256.     if (anErr == noErr)
  1257.         {
  1258.         long        imagewriterOptions = kSuperRes;
  1259.         
  1260.         anErr = AddCollectionItem(GXGetJobCollection(GXGetJob()), 
  1261.                     DriverCreator,
  1262.                     0,
  1263.                     sizeof(imagewriterOptions),
  1264.                     &imagewriterOptions);
  1265.                     
  1266.         }
  1267.  
  1268.  
  1269.     return(anErr);
  1270.     
  1271. } // SD_DefaultJob
  1272.  
  1273. /* ------------------------------------------------------------------------------------    */
  1274. OSErr SD_OpenConnection(void)
  1275. /*
  1276.     The OpenConnection message is sent in order to open the connection to the device.
  1277. */
  1278. {
  1279.     OSErr    anErr;
  1280.     
  1281.     // first, open the connection the standard way
  1282.     anErr = Forward_GXOpenConnection();
  1283.     nrequire(anErr, OpenConnection);
  1284.     
  1285.     // then, bring the configuration file up to date
  1286.     anErr = UpdateConfiguration();
  1287.     nrequire(anErr, UpdateConfiguration);
  1288.     
  1289.     return(noErr);
  1290.     
  1291. // EXCEPTION HANDLING
  1292. UpdateConfiguration:
  1293.     GXCleanupOpenConnection();
  1294.     
  1295. OpenConnection:
  1296.  
  1297.     return(anErr);
  1298.     
  1299. } // SD_OpenConnection
  1300.  
  1301. /* ------------------------------------------------------------------------------------    */
  1302. OSErr SD_CloseConnection(void)
  1303. {
  1304.     unsigned short    statusReturn;
  1305.     OSErr            anErr, anErr2;
  1306.     ResType            commType = (**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType;
  1307.  
  1308.     if (commType == 'PPTL')
  1309.         {
  1310.         // for PAP: wait for printer to finish printing so we can deal with the "out of paper case"
  1311.         do {
  1312.             anErr = FetchStatusString(&statusReturn, true, true);
  1313.             } while ((anErr == noErr) && ((statusReturn & kHeadMovingBit) != 0) );
  1314.         }
  1315.     else
  1316.         {
  1317.         // for serial: flush out all data so that we can query the printer properly    one last time
  1318.         anErr = Send_GXWriteData(nil, 0);
  1319.         nrequire(anErr, Send_GXWriteData);
  1320.         }
  1321.         
  1322.     // one last time check up on printer status 
  1323.     anErr2 = FetchStatusString(&statusReturn, (commType == 'PPTL'), true);
  1324.     if (anErr == noErr) anErr = anErr2;
  1325.     
  1326. Send_GXWriteData:
  1327.     // close the connection the standard way
  1328.     anErr2 = Forward_GXCloseConnection();
  1329.     if (anErr == noErr) anErr = anErr2;
  1330.         
  1331.     return(anErr);
  1332.     
  1333. } // SD_CloseConnection
  1334.  
  1335. /* ------------------------------------------------------------------------------------    */
  1336. OSErr SD_FreeBuffer(gxPrintingBuffer * theBuffer)
  1337. {
  1338.     OSErr    anErr;
  1339.     OSErr    firstError = noErr;
  1340.     
  1341.     if ((**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType == 'PPTL')
  1342.         {
  1343.         unsigned short    statusReturn;
  1344.         anErr = FetchStatusString(&statusReturn, true, true);
  1345.         nrequire(anErr, FetchStatusString);
  1346.         }
  1347.         
  1348.     do
  1349.         {
  1350.                 
  1351.         // try to send the buffer again
  1352.         anErr = Forward_GXFreeBuffer(theBuffer);
  1353.         if (firstError == noErr)
  1354.             firstError = anErr;
  1355.     
  1356.         // timeout dialog!
  1357.         if (anErr == gxAioTimeout)
  1358.             {
  1359.             gxStatusRecord        theStat, *pStat = &theStat;
  1360.             
  1361.             pStat->statResId     = kDriverStatus;        
  1362.             pStat->statResIndex = kCheckOnline;            
  1363.             pStat->bufferLen      = 0;
  1364.             pStat->dialogResult = 0;
  1365.                         
  1366.             // tell the user to check the printer
  1367.             (void) GXAlertTheUser(pStat);
  1368.                 
  1369.             // based on the user's response cancel
  1370.             if (pStat->dialogResult)
  1371.                 anErr = gxPrUserAbortErr;
  1372.             }
  1373.             
  1374.         } while (anErr == gxAioTimeout);
  1375.     
  1376.     // put down the timeout dialog, if we ever put one up
  1377.     if (firstError != noErr)
  1378.         (void) GXReportStatus(kDriverStatus, kSendingData);
  1379.  
  1380. FetchStatusString:        
  1381.     return(anErr);
  1382.     
  1383. } // SD_FreeBuffer
  1384.  
  1385. /* ------------------------------------------------------------------------------------    */
  1386. OSErr SD_DumpBuffer(gxPrintingBuffer * theBuffer)
  1387. {
  1388.     OSErr    anErr;
  1389.     
  1390.     if ((**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType == 'PPTL')
  1391.         {
  1392.         unsigned short    statusReturn;
  1393.         anErr = FetchStatusString(&statusReturn, true, true);
  1394.         nrequire(anErr, FetchStatusString);
  1395.         }
  1396.     anErr = Forward_GXDumpBuffer(theBuffer);
  1397.  
  1398. FetchStatusString:        
  1399.     return(anErr);
  1400.     
  1401. } // SD_DumpBuffer
  1402.  
  1403. /* ------------------------------------------------------------------------------------    */
  1404. OSErr SD_StartSendPage(gxFormat pageFormat)
  1405. /*
  1406.     The StartSendPage message is sent just before the page begins to be rendered.
  1407.     
  1408.     Note that the StartSendPage message will not be sent until imaging/communication
  1409.     time, so that user interaction alerts are considered okay here
  1410. */
  1411. {
  1412.     OSErr                        anErr = noErr;
  1413.     gxJob                        theJob = GXGetJob();
  1414.     Collection                    jobCollection;
  1415.     gxPaperFeedInfo                paperFeed;
  1416.     long                        itemSize = sizeof(paperFeed);
  1417.     ResType                        commType;
  1418.     unsigned short                statusReturn;
  1419.     
  1420.     check(theJob);
  1421.     jobCollection = GXGetJobCollection(theJob);
  1422.     check(jobCollection);
  1423.     
  1424.     // cache communications type
  1425.     commType = (**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType;
  1426.     if (commType == 'PPTL')
  1427.         {
  1428.         anErr = FetchStatusString(&statusReturn, true, true);
  1429.         nrequire(anErr, FetchStatusString);
  1430.         }
  1431.     else
  1432.         statusReturn = 0;
  1433.         
  1434.     // first, check to see if the entire job is auto feed.
  1435.     paperFeed.autoFeed = true;
  1436.     (void) GetCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, &itemSize, &paperFeed);
  1437.             
  1438.     // next, check to see if this particular page is to be manually fed
  1439.     if (!paperFeed.autoFeed)
  1440.         {
  1441.         // we now have the actual size of the paper feed item, so we get the manual feed list
  1442.         gxManualFeedInfo    **feedHandle;
  1443.         
  1444.         feedHandle = (gxManualFeedInfo**) NewHandle(0);
  1445.         anErr = MemError();
  1446.         nrequire(anErr, FailedNewHandle);
  1447.         
  1448.         anErr = GetCollectionItemHdl(jobCollection, gxManualFeedTag, gxPrintingTagID, (Handle)feedHandle);
  1449.         if (anErr == noErr)
  1450.             {
  1451.             Str31                paperName;
  1452.             short                idx;
  1453.             gxManualFeedInfo    *pFeed;
  1454.             
  1455.             // name of this page's paper type
  1456.             GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), paperName);
  1457.             
  1458.             // assume auto feed
  1459.             paperFeed.autoFeed = true;
  1460.             
  1461.             // lock and dereference for the loop
  1462.             HLockHi((Handle) feedHandle);
  1463.             pFeed = *feedHandle;
  1464.             
  1465.             // loop and see if one of our manual feed paperType's name matches
  1466.             for (idx = 0; idx < pFeed->numPaperTypeNames; ++idx) 
  1467.                 {
  1468.                 Ptr pName = (char *) pFeed->paperTypeNames[idx];
  1469.                 
  1470.                 if ( IUMagIDString(    paperName, 
  1471.                                             pName,
  1472.                                             paperName[0] + 1,
  1473.                                             *pName + 1)     == 0  ) 
  1474.                     {
  1475.                     paperFeed.autoFeed = false;
  1476.                     break;
  1477.                     }
  1478.                 }
  1479.             }
  1480.         
  1481.         DisposHandle((Handle) feedHandle);
  1482.         FailedNewHandle:
  1483.             ;
  1484.         }
  1485.         
  1486.     // manual feed or out of paper?  Time to ask the user what to do
  1487.     if     (     (!paperFeed.autoFeed)
  1488.         ||  ( ( (statusReturn & kOutOfPaperMask) != 0 ) )
  1489.         )
  1490.         {
  1491.         // Wait for all IO to complete, so that we can correctly tell the user what to do.
  1492.         // Since the WriteData message makes sure all data is flushed before performing the
  1493.         // IO, this call insures that pending IO is complete.
  1494.         anErr = Send_GXWriteData(nil, 0);
  1495.         nrequire(anErr, FlushAllData);
  1496.  
  1497.  
  1498.         // then, conduct the alert with the user
  1499.         {
  1500.         gxStatusRecord        *pStat;
  1501.         
  1502.         // make a status record containing the request to the user - note that 
  1503.         // we have to make room for ManualFeedRecord OR OutOfPaperRecord, but manual is bigger
  1504.         pStat = (gxStatusRecord *)NewPtrClear(sizeof(gxStatusRecord)  + sizeof(gxManualFeedRecord));
  1505.         anErr = MemError();
  1506.         nrequire(anErr, NewPtrClear);
  1507.                 
  1508.         pStat->statResId     = gxUnivAlertStatusResourceId;    // we use the built-in status for this
  1509.         pStat->dialogResult = 0;
  1510.         
  1511.         if (!paperFeed.autoFeed)
  1512.             {
  1513.             gxManualFeedRecord    *pFeed;
  1514.             
  1515.             pStat->statResIndex = gxUnivManualFeedIndex;            // status meaning "manual feed alert"
  1516.             pStat->bufferLen      = sizeof(gxManualFeedRecord);
  1517.             pFeed = (gxManualFeedRecord*)&pStat->statusBuffer;
  1518.         
  1519.             // we can switch to autofeed if we want - and tell the user what kind of paper to load in
  1520.             pFeed->canAutoFeed = true;
  1521.             GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), pFeed->paperTypeName);
  1522.             }
  1523.         else
  1524.             {
  1525.             gxOutOfPaperRecord    *pOut;
  1526.             
  1527.             pStat->statResIndex = gxUnivOutOfPaperIndex;            // status meaning "manual feed alert"
  1528.             pStat->bufferLen      = sizeof(gxOutOfPaperRecord);
  1529.             
  1530.             pOut = (gxOutOfPaperRecord*)&pStat->statusBuffer;
  1531.             GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), pOut->paperTypeName);
  1532.             }
  1533.             
  1534.         // keep sending the user the alert until either
  1535.         //  a) the problem resolves itself
  1536.         //  b) the user responds via the dialog
  1537.         //  c) some other (fatal) error happens
  1538.         do
  1539.             {
  1540.             
  1541.             // tell the user
  1542.             anErr = GXAlertTheUser(pStat);
  1543.             
  1544.             // if the paper got suddenly loaded, do an OK
  1545.             if (commType == 'PPTL')
  1546.                 {
  1547.                 (void) FetchStatusString(&statusReturn, true, true);
  1548.                 if ((statusReturn & kOutOfPaperMask) == 0)
  1549.                     {
  1550.                     pStat->dialogResult = ok;
  1551.                     anErr = noErr;
  1552.                     }
  1553.                 }
  1554.                 
  1555.             } while ((anErr == noErr) && (pStat->dialogResult == 0));
  1556.  
  1557.         // based on the user's response, continue, cancel, or switch to auto feed
  1558.         switch ( pStat->dialogResult )
  1559.             {
  1560.             case ok:
  1561.                 // paper is loaded
  1562.                 break;
  1563.                 
  1564.             case cancel:
  1565.                 // user wishes to stop the printing process
  1566.                 anErr = gxPrUserAbortErr;
  1567.                 break;
  1568.                 
  1569.             case gxAutoFeedButtonId:
  1570.                 // do rest of job with auto feed
  1571.                 paperFeed.autoFeed = true;
  1572.                 (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, itemSize, &paperFeed);
  1573.                 break;
  1574.                 
  1575.             } // switch
  1576.             
  1577.             
  1578.         // done with the status now
  1579.         DisposPtr((Ptr) pStat);
  1580.         }
  1581.             
  1582.         } // if manual feed job
  1583.         
  1584.     // display "sending data to the printer" message
  1585.     if (anErr == noErr)
  1586.         anErr = GXReportStatus(kDriverStatus, kSendingData);
  1587.         
  1588.     nrequire(anErr, FailedWaitForPaper);
  1589.         
  1590.     // continue with the standard starting of the page
  1591.     anErr = Forward_GXStartSendPage(pageFormat);
  1592.         
  1593.         
  1594. // FALL THROUGH AND HANDLE EXCEPTIONS
  1595.  
  1596. FailedWaitForPaper:
  1597. NewPtrClear:
  1598. FlushAllData:
  1599. FetchStatusString:
  1600.     return(anErr);
  1601.     
  1602. } // SD_StartSendPage
  1603.  
  1604. /* ------------------------------------------------------------------------------------    */
  1605. OSErr SD_FinishSendPage()
  1606. {
  1607.     OSErr        anErr = noErr;
  1608.     Str63        formLength;            // should be more than big enough for form skipping
  1609.     char        len = 0;
  1610.  
  1611.     // we may have issued line feeds RIGHT up to the end of the page.  If
  1612.     // we do that and then issue a form feed, we'll kick out a blank page.
  1613.     // to avoid that, we back up a tad and then let the normal form feed
  1614.     // go through.  Option 2 would be to track each and every motion control
  1615.     // we send to the printer -- but that's more work than this.  In addition,
  1616.     // this method makes sure we are synced up exactly to the hardware
  1617.     formLength[len++] = ESCAPE;
  1618.     formLength[len++] = 'T';
  1619.     formLength[len++] = '0';
  1620.     formLength[len++] = '1';
  1621.     formLength[len++] = ESCAPE;
  1622.     formLength[len++] = 'r';
  1623.     formLength[len++] = 0x0A;
  1624.     
  1625.     // reset to forward motion for the form feed
  1626.     formLength[len++] = ESCAPE;
  1627.     formLength[len++] = 'f';
  1628.     
  1629.     anErr = Send_GXBufferData((char *) &formLength[0], len, gxNoBufferOptions );
  1630.     nrequire(anErr, Send_GXBufferData);
  1631.     
  1632.     // Default implementation provides the actual form feed
  1633.     anErr = Forward_GXFinishSendPage();
  1634.     
  1635. // FALL THROUGH EXCEPTION HANDLING
  1636. Send_GXBufferData:
  1637.  
  1638.     return(anErr);
  1639.     
  1640. } // SD_FinishSendPage
  1641.  
  1642.  
  1643. /* ------------------------------------------------------------------------------------    */
  1644. OSErr SD_FormatDialog(gxFormat theFormat, StringPtr title, gxDialogResult *theResult)
  1645. /*
  1646.     This message is sent in response to the user's
  1647.     request to put up a page formatting dialog.
  1648. */
  1649. {
  1650.     OSErr    err;
  1651.  
  1652.     err = NewMessageGlobals(A5Size(), A5Init);
  1653.     nrequire(err, NewMessageGlobals_Failed);
  1654.  
  1655.     err = SetupFormatPanel(r_FlipPanel2, theFormat);
  1656.     nrequire(err, CouldNotSetUpPanel);
  1657.  
  1658.     err = Forward_GXFormatDialog(theFormat, title, theResult);
  1659.     TearDownFormatPanel(*theResult, theFormat);
  1660.  
  1661. CouldNotSetUpPanel:
  1662.     DisposeMessageGlobals();
  1663.  
  1664. NewMessageGlobals_Failed:    
  1665.     return err;
  1666. }
  1667.  
  1668.  
  1669. /* ------------------------------------------------------------------------------------    */
  1670. OSErr SD_JobFormatDialog(gxDialogResult*    theResult)
  1671. /*
  1672.     This message is sent in response to the user's request to put up a formatting dialog
  1673. */
  1674. {
  1675.     OSErr                     anErr;
  1676.     gxJobFormatModeTableHdl    theJobFormatModeList;
  1677.     long                    i;
  1678.     gxJob                     theJob = GXGetJob();
  1679.  
  1680.     anErr = NewMessageGlobals(A5Size(), A5Init);
  1681.     nrequire(anErr, NewMessageGlobals_Failed);
  1682.  
  1683.     anErr = SetupFormatPanel(r_FlipPanel, GXGetJobFormat(theJob, 1));
  1684.     nrequire(anErr, CouldNotSetUpPanel);
  1685.     
  1686.     // set up the JobFormatMode information
  1687.     
  1688.     anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
  1689.     if ((!anErr) && (theJobFormatModeList))
  1690.         {
  1691.         for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i) 
  1692.             {
  1693.             if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode) 
  1694.                 {
  1695.                 GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
  1696.                 break;
  1697.                 }
  1698.             }
  1699.         DisposHandle((Handle)theJobFormatModeList);
  1700.         }
  1701.         
  1702.     // do the normal dialogs after handling the job format mode stuff
  1703.     anErr = Forward_GXJobDefaultFormatDialog(theResult);
  1704.     
  1705.     TearDownFormatPanel(*theResult, GXGetJobFormat(theJob, 1));
  1706.  
  1707. CouldNotSetUpPanel:
  1708.     DisposeMessageGlobals();
  1709.  
  1710. NewMessageGlobals_Failed:    
  1711.     return anErr;
  1712.  
  1713. } // SD_JobFormatDialog
  1714.  
  1715. /* ------------------------------------------------------------------------------------    */
  1716. OSErr SD_JobFormatModeQuery(    gxQueryType        theQuery,
  1717.                                 void*            srcData,
  1718.                                 void*            dstData)
  1719. /*
  1720.     This message is sent to find out information about the current job format mode.
  1721. */
  1722. {
  1723.     OSErr        anErr = noErr;
  1724.     Handle        theFonts;
  1725.     Handle        theStyles;
  1726.     
  1727.     check(dstData != nil);
  1728.     
  1729.     // What type of query is being requested?
  1730.     switch(theQuery) 
  1731.     {
  1732.         case gxSetStyleJobFormatCommonStyleQuery:
  1733.         {
  1734.             char                *pStyleName;
  1735.  
  1736.             // Fetch the list of supported styles
  1737.             
  1738.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1739.             require(anErr == noErr, FailedToLoadStyles1);
  1740.             
  1741.             HNoPurge(theStyles);
  1742.             HLock(theStyles);
  1743.             
  1744.             // Determine which style is being referenced and set the corresponding style (only 2 styles
  1745.             // are currently supported)
  1746.             
  1747.             if (**((short **) theStyles) == 2)    //    T => We have the correct number of styles
  1748.             {
  1749.                 char        whichFace = 0;
  1750.                 
  1751.                 pStyleName = ((char *) *theStyles) + sizeof(short); 
  1752.                 
  1753.                 if ( IUCompString((unsigned char const *) pStyleName, srcData) == 0 )    //    T => They want bold face
  1754.                 {
  1755.                     whichFace = bold;
  1756.                 }
  1757.                 else
  1758.                 {
  1759.                     // Point to the next name in the list
  1760.                     pStyleName += *pStyleName + 1;
  1761.  
  1762.                     if ( IUCompString((unsigned char const *) pStyleName, srcData) == 0 )    //    T => They want underline face
  1763.                     {
  1764.                         whichFace = underline;
  1765.                     }
  1766.                 }
  1767.  
  1768.                 //    If the client specified a valid face, set it now
  1769.                 if (whichFace != 0)
  1770.                 {
  1771.                     SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
  1772.                 }
  1773.             }
  1774.             // else - something is wrong with our resource
  1775.             
  1776.             // Dump the temporary handle
  1777.             DisposHandle(theStyles);
  1778.             
  1779.             break;
  1780.         }
  1781.             
  1782.         case gxGetJobFormatFontCommonStylesQuery:
  1783.         {
  1784.             short                numStyles;
  1785.             short                i;
  1786.             char                *pStyleName;
  1787.  
  1788.             // Fetch the list of supported styles
  1789.             
  1790.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1791.             require(anErr == noErr, FailedToLoadStyles2);
  1792.             
  1793.             HNoPurge(theStyles);
  1794.             HLock(theStyles);
  1795.             
  1796.             // Determine the number of styles in the list
  1797.             numStyles = **((short **) theStyles);
  1798.  
  1799.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the styles
  1800.                 SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1801.             else
  1802.                 *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1803.             
  1804.             anErr = MemError();
  1805.             require(anErr == noErr, StyleTableResizeFailed);
  1806.             
  1807.             // Now extract the name of each of the supported fonts
  1808.             
  1809.             for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
  1810.             {
  1811.                 BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
  1812.             }
  1813.             
  1814.             (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
  1815.             
  1816.             // Dump the temporary handle
  1817.             DisposHandle(theStyles);
  1818.             
  1819.             break;
  1820.         }
  1821.             
  1822.         case gxGetJobFormatLineConstraintQuery:            //    This type of query is not supported
  1823.             if (*(Handle *)dstData != nil)
  1824.                 SetHandleSize(*(Handle *)dstData, 0);        // Don't return any data
  1825.             break;
  1826.             
  1827.         case gxGetJobFormatFontsQuery:
  1828.         {
  1829.             short                numFonts;
  1830.             short                i;
  1831.             char                *pFontName;
  1832.  
  1833.             // Fetch the list of supported fonts
  1834.             
  1835.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
  1836.             require(anErr == noErr, FailedToLoadFonts);
  1837.             
  1838.             HNoPurge(theFonts);
  1839.             HLock(theFonts);
  1840.             
  1841.             // Determine the number of fonts in the list
  1842.             numFonts = **((short **) theFonts);
  1843.  
  1844.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the fonts
  1845.                 SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1846.             else
  1847.                 *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1848.             
  1849.             anErr = MemError();
  1850.             require(anErr == noErr, FontTableResizeFailed);
  1851.             
  1852.             // Now generate a reference to each of the supported fonts
  1853.             
  1854.             for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
  1855.             {
  1856.                 gxFont            thisFont;
  1857.                 gxFontTable        *pFontTable;
  1858.             
  1859.                 thisFont = FindPNameFont(gxFullFontName, (unsigned char const *) pFontName);
  1860.                 
  1861.                 pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
  1862.                 pFontTable->fonts[i - 1] = thisFont;
  1863.             }
  1864.             
  1865.             (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
  1866.             
  1867.             // Dump the temporary handle
  1868.             DisposHandle(theFonts);
  1869.  
  1870.             break;
  1871.         }
  1872.             
  1873.         case gxGetJobFormatFontConstraintQuery:
  1874.         {
  1875.             gxPositionConstraintTable        *pPositionTable;
  1876.             
  1877.             if ( *(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on position constraints
  1878.                 SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
  1879.             else
  1880.                 *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
  1881.             
  1882.             pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
  1883.             
  1884.             pPositionTable->phase.x     = 0;                //    Start at the top left corner of the page
  1885.             pPositionTable->phase.y     = 0;
  1886.             pPositionTable->offset.x     = ff(12);        // Indent from the top left by a six lines per inch margin
  1887.             pPositionTable->offset.y     = ff(12);         
  1888.             pPositionTable->numSizes     = 2;                // Two font sizes supported
  1889.             pPositionTable->sizes[0]     = ff(10);         // 10 pitch
  1890.             pPositionTable->sizes[1]     = ff(12);         // 12 pitch
  1891.             
  1892.             break;
  1893.         }
  1894.     } // switch
  1895.     
  1896.     return(anErr);
  1897.     
  1898.  
  1899. /******* Clean-up *******/
  1900.  
  1901. StyleTableResizeFailed:
  1902.     DisposHandle((Handle) theStyles);
  1903.     return(anErr);
  1904.  
  1905. FontTableResizeFailed:
  1906.     DisposHandle((Handle) theFonts);
  1907.  
  1908. FailedToLoadStyles1:
  1909. FailedToLoadStyles2:
  1910. FailedToLoadFonts:
  1911.     return(anErr);
  1912.     
  1913. } // SD_JobFormatModeQuery
  1914.  
  1915. //<FF>
  1916. /* ------------------------------------------------------------------------------------    */
  1917. OSErr SD_SetupImageData(
  1918.     gxRasterImageDataHdl hImageData)        // raster image data stuff
  1919. /*
  1920.     This message is called to setup the constant data used for imaging the entire job.
  1921. */
  1922. {
  1923.  
  1924.     SpecGlobalsHdl                 hGlobals = GetMessageHandlerInstanceContext();
  1925.     OSErr                        anErr;
  1926.     gxRasterImageDataPtr        pImageData;
  1927.     Boolean                     isJobNotFinalQuality, isTextJobFormatMode;
  1928.     long                        imagewriterOptions;
  1929.     
  1930.     // do the default setup
  1931.     anErr = Forward_GXSetupImageData(hImageData);
  1932.     nrequire(anErr, Forward_GXSetupImageData);
  1933.     
  1934.     // test for 'final' quality mode
  1935.     isJobNotFinalQuality = !JobIsBest(&imagewriterOptions);
  1936.     
  1937.     // test for textJobFormatMode
  1938.     isTextJobFormatMode = ( GXGetJobFormatMode( GXGetJob() ) == gxTextJobFormatMode);
  1939.             
  1940.     // if the job is not final quality or using textJobFormatMode, downgrade the imaging data to our lower quality
  1941.     if (isJobNotFinalQuality  ||  isTextJobFormatMode)
  1942.         {
  1943.         // ROUGH OR TEXT MODE
  1944.         
  1945.         // dereference for size and speed    
  1946.         pImageData = *hImageData;
  1947.                 
  1948.         // image at 80 or 72 dpi
  1949.         if (imagewriterOptions & kSuperRes)
  1950.             pImageData->hImageRes = ff(80);
  1951.         else
  1952.             pImageData->hImageRes = ff(72);
  1953.         pImageData->vImageRes = ff(72);
  1954.         
  1955.         // textJobFormatMode loads up the draft table, else setup halftones
  1956.         if (isTextJobFormatMode)
  1957.             {
  1958.             Handle            draftTable;
  1959.  
  1960.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
  1961.             nrequire(anErr, FailedToLoadDraftTable);
  1962.             
  1963.             // store away the draft table
  1964.             (**hGlobals).draftTable = draftTable;
  1965.  
  1966.             // Download something?    
  1967.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID+1, &draftTable);
  1968.             if (anErr == resNotFound)
  1969.                 {
  1970.                 draftTable = nil;
  1971.                 anErr = noErr;
  1972.                 }
  1973.             nrequire(anErr, GetDownloadTable);    
  1974.         
  1975.             if (draftTable)
  1976.                 {
  1977.                 HLock(draftTable);
  1978.                 anErr = Send_GXBufferData(*draftTable, GetHandleSize(draftTable), gxDontSplitBuffer);
  1979.                 DisposHandle(draftTable);
  1980.                 nrequire(anErr, SendDownloadTable);
  1981.                 }
  1982.             }
  1983.         else
  1984.             {            
  1985.             // use dither level that will look better at 72 dpi 
  1986.             // resolution than our default values (MAYBE: 4 is the default now anyway)
  1987.             pImageData->theSetup.planeSetup[0].planeHalftone.method = 4;
  1988.             
  1989.             // of course, turn off color matching when in non-final mode!
  1990.             pImageData->theSetup.planeSetup[0].planeProfile = nil;
  1991.             }
  1992.             
  1993.         if (isJobNotFinalQuality)
  1994.             {
  1995.             if (imagewriterOptions & kSuperRes)
  1996.                 {
  1997.                 // use bidirectional instead of unidirectional
  1998.                 // and also <esc>N instead of <esc>p for quality mode
  1999.                 pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+3;
  2000.                 }
  2001.             else
  2002.                 {
  2003.                 // use bidirectional instead of unidirectional
  2004.                 // and also <esc>n instead of <esc>p for quality mode
  2005.                 pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+2;
  2006.                 }
  2007.             }
  2008.         
  2009.         // packaging data
  2010.         pImageData->packagingInfo.headHeight         = 8;        // 8 pins (instead of 16)
  2011.         pImageData->packagingInfo.numberPasses         = 1;        // in 1 head pass (instead of 2)
  2012.         pImageData->packagingInfo.passOffset         = 0;        // with no space between passes
  2013.         }
  2014.     else
  2015.         {
  2016.         // FINAL QUALITY
  2017.         
  2018.         // dereference for size and speed    
  2019.         pImageData = *hImageData;
  2020.                 
  2021.         // image at 160 or 144 dpi
  2022.         if (imagewriterOptions & kSuperRes)
  2023.             {
  2024.             pImageData->hImageRes = ff(160);
  2025.             pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+1;
  2026.             }
  2027.         else
  2028.             {
  2029.             pImageData->hImageRes = ff(144);
  2030.             pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+0;
  2031.             }
  2032.         }
  2033.     
  2034.     // not a color ribbon?  Setup for black and white - do a B/W halftone rather than a dither
  2035.     if (!PrinterHasColorRibbon(GXGetJobOutputPrinter(GXGetJob())))
  2036.         {
  2037.         // dereference for size and speed    
  2038.         pImageData = *hImageData;
  2039.  
  2040.         // one plane, no color flags, move the halftone info up into correct position
  2041.         pImageData->theSetup.planes = 1;
  2042.         pImageData->theSetup.depth = 1;
  2043.         pImageData->packagingInfo.colorPasses = 1;
  2044.         pImageData->packagingInfo.packageOptions = 0;
  2045.         pImageData->theSetup.planeSetup[0].planeSpace = gxNoSpace;
  2046.         pImageData->theSetup.planeSetup[0].planeSet = nil;
  2047.         pImageData->theSetup.planeSetup[0].planeProfile = nil;
  2048.         pImageData->theSetup.planeSetup[0].planeOptions = gxDefaultOffscreen;
  2049.         pImageData->theSetup.planeSetup[0].planeHalftone.method = gxRoundDot;
  2050.         pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
  2051.         }
  2052.  
  2053.     return(noErr);
  2054.     
  2055. // EXCEPTION HANDLING
  2056. SendDownloadTable:
  2057. GetDownloadTable:
  2058.     DisposHandle((**hGlobals).draftTable);
  2059.     (**hGlobals).draftTable = nil;
  2060.     
  2061. FailedToLoadDraftTable:
  2062. Forward_GXSetupImageData:
  2063.     return(anErr);
  2064.     
  2065. } // SD_SetupImageData
  2066.  
  2067. /* ------------------------------------------------------------------------------------    */
  2068. OSErr SD_FetchDriverData(
  2069.     ResType            theType,
  2070.     short            theID,
  2071.     Handle*            theData)
  2072. {
  2073.  
  2074.     OSErr    anErr;
  2075.     
  2076.     anErr = Forward_GXFetchTaggedDriverData(theType, theID, theData);
  2077.     
  2078.     // do the translation at the proper DPI by modifying the old API
  2079.     // customization resource
  2080.     if ( (anErr   == noErr)    &&                 // got the resource okay
  2081.          (theType == 'cust')   &&                // it was a customization resource 
  2082.          (theID   == -8192)   )                    // with the old API id
  2083.         {
  2084.         long imagewriterOptions;
  2085.         
  2086.         if (!JobIsBest(&imagewriterOptions))
  2087.             {
  2088.             **((short**)theData)   = 72;
  2089.             **((short**)theData+1) = 72;
  2090.             }
  2091.         }
  2092.         
  2093.     return(anErr);
  2094.     
  2095. } // SD_FetchDriverData
  2096.  
  2097.  
  2098. /* ------------------------------------------------------------------------------------    */
  2099. OSErr SD_RenderPage(    gxFormat                theFormat,
  2100.                         gxShape                    thePage,
  2101.                         gxPageInfoRecord        *pageInfo,
  2102.                         gxRasterImageDataHdl    imageInfo)
  2103. /*
  2104.     The message sent to render an entire page.
  2105. */
  2106. {
  2107.  
  2108.     OSErr    theError = noErr;
  2109.  
  2110.     // if not text mode, do it the normal (raster) way
  2111.     if (GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode) 
  2112.         {
  2113.         gxRectangle            paperSize;
  2114.         Str63                formLength;            // should be more than big enough for form skipping
  2115.         char                aNumber[8];
  2116.         char                len = 0;
  2117.         short                formLen;            // form length (in 144 dpi)
  2118.         short                i;
  2119.         
  2120.         
  2121.         // find out how big our paper is
  2122.         GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
  2123.         
  2124.         // determine the left margin (in pixels)
  2125.         {
  2126.         SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  2127.         SpecGlobalsPtr            pGlobals;
  2128.         gxRasterImageDataPtr    pImageData;
  2129.  
  2130.         check(hGlobals);
  2131.  
  2132.         // dereference for size and speed    
  2133.         pImageData     = *imageInfo;
  2134.         pGlobals = *hGlobals;
  2135.         paperSize.left += ff(18);        // ImageWriter's can't go tighter than .25 inch
  2136.         if (paperSize.left > 0)
  2137.             paperSize.left = 0;
  2138.         pGlobals->leftMargin     = FixedToInt(
  2139.                                     FixMul(-paperSize.left, 
  2140.                                         FixDiv(pImageData->hImageRes, ff(72))));
  2141.         }
  2142.         
  2143.         // move over the top margin, set the form length to be the size of the page
  2144.         
  2145.         // form length == top margin
  2146.         formLen = FixedToInt(FixMul(-paperSize.top, ff(2)) );                    // length is set in 144 dpi
  2147.         if (formLen > 0)
  2148.             {
  2149.             // Forward line feed
  2150.             formLength[len++] = ESCAPE;
  2151.             formLength[len++] = 'f';
  2152.  
  2153.             // send multiples of 99
  2154.             if (formLen >= 99)
  2155.                 {
  2156.                 formLength[len++] = ESCAPE;
  2157.                 formLength[len++] = 'T';
  2158.                 formLength[len++] = '9';
  2159.                 formLength[len++] = '9';
  2160.                 while (formLen >= 99)
  2161.                     {
  2162.                     formLength[len++] = 0x0A;        // line feed
  2163.                     
  2164.                     formLen -= 99;
  2165.                     }
  2166.                 }
  2167.                 
  2168.             // send remaining line feeds
  2169.             if (formLen > 0)
  2170.                 {
  2171.                 formLength[len++] = ESCAPE;
  2172.                 formLength[len++] = 'T';
  2173.                 NumToString(formLen, (unsigned char *) aNumber);
  2174.                 if (aNumber[0] == 1)
  2175.                     {
  2176.                     formLength[len++] = '0';
  2177.                     formLength[len++] = aNumber[1];
  2178.                     }
  2179.                 else
  2180.                     {
  2181.                     formLength[len++] = aNumber[1];
  2182.                     formLength[len++] = aNumber[2];
  2183.                     }
  2184.                 formLength[len++] = 0x0A;        // line feed
  2185.                 }
  2186.             }
  2187.         
  2188.         // form length == page size - top margin (which we already moved over)
  2189.         // BUT, since the top margin is a negative number we add it to the bottom
  2190.         // in order to subtract it
  2191.         formLength[len++] = ESCAPE;
  2192.         formLength[len++] = 'H';
  2193.         formLen = FixedToInt(FixMul(paperSize.bottom+paperSize.top, ff(2)) );    // length is set in 144 dpi
  2194.         NumToString(formLen, (unsigned char *) aNumber);
  2195.         for (i = 0; i < 4-aNumber[0]; ++i)
  2196.             formLength[len++] = '0';
  2197.         for (i = 1; i <= aNumber[0]; ++i)
  2198.             formLength[len++] = aNumber[i];
  2199.         
  2200.         // set this to be the top of form
  2201.         formLength[len++] = ESCAPE;
  2202.         formLength[len++] = 'v';
  2203.  
  2204.         // we've got all of this data, now send it
  2205.         theError = Send_GXBufferData((char *) &formLength[0], len, gxNoBufferOptions );
  2206.         nrequire(theError, SetFormLength);        
  2207.                 
  2208.         // continue with normal rendering
  2209.         theError = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageInfo);
  2210.         } 
  2211.     else 
  2212.         {
  2213.         theError = PrintPageInDraftMode(thePage, imageInfo);
  2214.         }
  2215.  
  2216. failed_WrongShape:
  2217. SetFormLength:
  2218.     return(theError);
  2219.     
  2220. } // SD_RenderPage
  2221.  
  2222.  
  2223. //<FF>
  2224. /* ------------------------------------------------------------------------------------    */
  2225. /*    SPECIFIC DRIVER RASTER OVERRIDES                                                    */
  2226. /* ------------------------------------------------------------------------------------    */
  2227. OSErr SD_LineFeed (
  2228.     short *lineFeedSize,                         // amount to line feed by
  2229.     Ptr buffer, unsigned long    * bufferPos,     // data goes here
  2230.     gxRasterImageDataHdl hImageData)            // raster image data stuff
  2231. /*
  2232.     Message is sent to output paper advance commands to the printer
  2233. */
  2234. {
  2235.  
  2236.     OSErr    anErr;
  2237.     Boolean    amLowRes;
  2238.     long    actualLineFeed = *lineFeedSize;
  2239.     
  2240.     amLowRes = ((**hImageData).vImageRes == ff(72));
  2241.     // if we are in low res mode, we double the line feed size, as all ImageWriter 
  2242.     // line feed commands are expressed at 144 dpi.
  2243.     if (amLowRes)
  2244.         *lineFeedSize <<= 1;
  2245.     
  2246.     // optimize small motions (particularlly -1 followed by +1 with no data between)
  2247.     // into groups.  This gets rid of the "paper dance" for blank colors passes.
  2248.     {    
  2249.     SpecGlobalsHdl    hGlobals = GetMessageHandlerInstanceContext();
  2250.     SpecGlobalsPtr    pGlobals = *hGlobals;
  2251.     
  2252.     if (    (pGlobals->packagingOptions == kDoSmallLineFeeds) || 
  2253.             (*lineFeedSize < -1) || 
  2254.             (*lineFeedSize > 1) )
  2255.         {
  2256.         *lineFeedSize += pGlobals->lineFeeds;
  2257.         pGlobals->lineFeeds = 0;
  2258.         // do the line feed in the default way
  2259.         anErr = Forward_GXRasterLineFeed(&actualLineFeed, buffer, bufferPos, hImageData);
  2260.         }
  2261.     else
  2262.         {
  2263.         pGlobals->lineFeeds += *lineFeedSize;
  2264.         *lineFeedSize = 0;
  2265.         anErr = noErr;
  2266.         }
  2267.     }
  2268.     
  2269.     // and if in low quality mode, we divide the result to make up for the multiplication
  2270.     // that we do above
  2271.     if (amLowRes)
  2272.         *lineFeedSize >>= 1;    
  2273.             
  2274.     return(anErr);
  2275.     
  2276. } // SD_LineFeed
  2277.  
  2278. //<FF>
  2279. /* ------------------------------------------------------------------------------------    */
  2280. OSErr SD_PackageBitmap (
  2281.     gxRasterPackageBitmapRec    *pPackage,
  2282.     Ptr                         buffer,     // data goes here + bufferPos
  2283.     unsigned long                 *bufferPos,    // how much of the buffer already is full
  2284.     gxRasterImageDataHdl         hImageData)    // private image data
  2285. /*
  2286.     Packages a bitmap for the ImageWriter
  2287.     This routine is called in order to add your rotated and packaged pixel
  2288.     data to the buffer.  It is called once for each head pass.  This routine
  2289.     is pretty complex because it also does IW run length compression.  
  2290.     
  2291.     It must do the following:
  2292.         
  2293.     1)    Start filling the buffer from buffer+bufferPos.  Remember
  2294.         that this pointer may not be word aligned - so be careful
  2295.         assigning things into it.
  2296.         
  2297.     2)    If your printer does SetMargins, put a "fake" set of commands at
  2298.         the begining of the data.  Since most of the time you don't
  2299.         know the margins, you can save away the value of the bufferPos,
  2300.         and backpatch it after you have finished with the offscreen.
  2301.         SetMargins is used on printers that allow you to not send starting
  2302.         and ending whitespace.
  2303.         
  2304.     3)    Add in the rotated data for your printer.  The data to stuff starts
  2305.         at location startY in hOffscreen.  Stuff the bits from here until
  2306.         you reach startY+<your band size>, which is the size of your single
  2307.         band in this resolution mode.  Increment your number by 
  2308.         <your pass offset> + 1, which is the number of microspaces
  2309.         you will send between head passes to form this band.   Take care
  2310.         that you don't step off of the end of the offscreen in this operation,
  2311.         you may be called with startY at the end of the offscreen if the first part
  2312.         of the band is white.
  2313.         
  2314.         colorBand contains the color band which you should be stuffing, from
  2315.         1 to the number of color passes your printer needs (usually 4).
  2316.         Pack in the correct color band.  The packager will call you once
  2317.         for each color band, and correctly handle line feeds and backward
  2318.         line feeds to do the correct thing.  If your printer takes full
  2319.         RGB or CYMK data, I would define your number of colors to be
  2320.         1 and pack the full RGB or CYMK data with the one call to StuffBuffers.
  2321.         
  2322.         If you request kSendAllColors in your raster pack resource, then this
  2323.         message will always be called for all color passes, even those that
  2324.         do not have data on them.  For some printers, this is useful.  For the
  2325.         case of the ImageWriter, this option is not specified, so this message
  2326.         will only be sent for colors that actually have dirty bits within them.
  2327.         
  2328.     4)    Backpatch SetMargins from your saved value in step 2) now that you
  2329.         know the margins.
  2330.         
  2331.     5)    Increment bufferPos by the number of bytes you have
  2332.         added to the buffer.  Be sure to take into account the Set Margins
  2333.         command if you added one.
  2334.  
  2335.     
  2336. */
  2337. {
  2338. #pragma unused (isColorDirty)
  2339.  
  2340.     OSErr                    anErr;            // would you beleive we could make mistakes?
  2341.     ScanLinePtr                pTheScanLine;    // Pointer to the start of scan line data
  2342.     unsigned short            lastDirtyCol;    // Last dirty part of the scan line
  2343.     unsigned short            firstDirty;        // First dirty pixel
  2344.     unsigned short            lastDirty;        // Last dirty pixel
  2345.     Boolean                    bandIsDirty;    // Is this band dirty?
  2346.     unsigned short            numberBytesAdded;// Number of bytes we have added to the row
  2347.     unsigned short            repeatCount;    // Number of times we have seen this bitmap
  2348.     
  2349.     register unsigned short    whichCol;        // Index into the scan line data
  2350.     register unsigned short    x,y;            // Index values into the offscreen
  2351.         
  2352.     register Ptr            thePtr;            // Pointer to each Y scanline
  2353.     register unsigned char    tempColumn;        // Placeholder for the working column
  2354.     unsigned char            lastColumn;        // What was in the contents of the last column?
  2355.     
  2356.     Ptr                basePtr;        // Pointer to current X byte
  2357.     unsigned char    outputMask;        // Mask of bit to set in rotated image
  2358.     unsigned char    inputMask;        // Mask of bit to look at in X
  2359.     unsigned char    startingInputMask;// Mask of first bit of interest
  2360.     unsigned short    yPointerOffset;    // Increment pointer by this to get to next scanline
  2361.     
  2362.     unsigned short    endY, endX, incrY;    // To remove loop invariants.
  2363.     unsigned short    packingColor;        // number of colors packing
  2364.     unsigned long    originalBufferPos;    // where we were in the buffer before we started;
  2365.     long            originalLineFeeds;    // how many line feeds did we have before?
  2366.     SpecGlobalsHdl    hGlobals = GetMessageHandlerInstanceContext();
  2367.     SpecGlobalsPtr    pGlobals = *hGlobals;
  2368.     
  2369. /* This macro stores one group into the pointer:
  2370.     P = Pointer to fill into
  2371.     G = Character for group
  2372.     S = Length of group run in pixels
  2373. */
  2374. #define EMITGROUP(P, G, S)                    \
  2375.         P->cEscape = ESCAPE;                \
  2376.         P->cCommand = G;                    \
  2377.         Long2Dec(S, P->cLineLength);        
  2378.  
  2379.     // save away original position in order to do a restore should the band be clean
  2380.     originalBufferPos = *bufferPos;
  2381.     originalLineFeeds = pGlobals->lineFeeds;
  2382.     if (originalLineFeeds == 0)
  2383.         {
  2384.         anErr = noErr;
  2385.         }
  2386.     else
  2387.         {
  2388.         // if we have any extra line feeds saved up, do them now!    
  2389.         pGlobals->lineFeeds = 0;
  2390.         pGlobals->packagingOptions = kDoSmallLineFeeds;
  2391.         anErr = Send_GXRasterLineFeed(&originalLineFeeds, buffer, bufferPos, hImageData);
  2392.         pGlobals = *hGlobals;
  2393.         pGlobals->packagingOptions = kNoPackagingOptions;
  2394.         }
  2395.     nrequire(anErr, SendInitialLineFeeds);
  2396.     
  2397.     pTheScanLine = (ScanLinePtr) (buffer + kSetMarginsSize + (*bufferPos));
  2398.     
  2399.     /* Set color mode for this scan line, if needed */
  2400.     pTheScanLine->cColorEscape        = ESCAPE;
  2401.     pTheScanLine->cSetColorCommand    = kSetColorCommand;
  2402.     
  2403.     packingColor = (*hImageData)->packagingInfo.colorPasses;
  2404.     if (packingColor == 4)
  2405.         switch (pPackage->colorBand)
  2406.             {
  2407.             case 1: // yellow
  2408.                 pTheScanLine->cColor    = '1';
  2409.                 startingInputMask = 0x10;
  2410.                 break;
  2411.                 
  2412.             case 2: // magenta
  2413.                 pTheScanLine->cColor    = '2';
  2414.                 startingInputMask = 0x20;
  2415.                 break;
  2416.  
  2417.             case 3: // cyan
  2418.                 pTheScanLine->cColor    = '3';
  2419.                 startingInputMask = 0x40;
  2420.                 break;
  2421.                 
  2422.             case 4: // black
  2423.                 pTheScanLine->cColor    = '0';
  2424.                 startingInputMask = 0x80;
  2425.                 break;
  2426.                 
  2427.             }
  2428.     else
  2429.         {
  2430.         pTheScanLine->cColor = '0';
  2431.         startingInputMask = 0x80;
  2432.         }
  2433.  
  2434.     /* Start with the first bit in the offscreen */
  2435.     inputMask = startingInputMask;
  2436.         
  2437.     /* We start out with no dirty bits */
  2438.     firstDirty = 0;
  2439.     lastDirty = 0;
  2440.     bandIsDirty = false;
  2441.     
  2442.     /* Set our array index to zero */
  2443.     whichCol = 0;
  2444.     lastDirtyCol = 0;
  2445.     numberBytesAdded = 0;
  2446.     
  2447.     /* Set up RLL variables */
  2448.     repeatCount = 0;
  2449.     lastColumn = 0;
  2450.     
  2451.     /* Get the byte pointer for the start of this color band */
  2452.     basePtr = pPackage->bitmapToPackage->image;
  2453.     
  2454.     /* Get the byte pointer for the start of the first scan line */ 
  2455.     basePtr += pPackage->startRaster * pPackage->bitmapToPackage->rowBytes;
  2456.             
  2457.     /* Save away loop invariants */
  2458.     endY     = pPackage->startRaster + (*hImageData)->packagingInfo.headHeight;        // Ending scan line
  2459.     incrY     = (*hImageData)->packagingInfo.passOffset + 1;            // Number of scanlines to increment by
  2460.     endX     = pPackage->dirtyRect.right;                                // Ending X pos
  2461.     yPointerOffset = incrY * pPackage->bitmapToPackage->rowBytes;            // amount to add to the input
  2462.                                                             // pointer to move to the next scanline
  2463.  
  2464.     /* If the ending position is too large for the bitmap we have been given,
  2465.        truncate it, so that we don't print garbage */
  2466.     if (endY > pPackage->bitmapToPackage->height)
  2467.         endY = pPackage->bitmapToPackage->height;
  2468.     
  2469.     /* For the entire width of the offscreen, move a rolling mask along in the
  2470.        X direction, rotating up 8 bits of Y data per column.  In addition, compress
  2471.        runs of columns that are > 14 length. */
  2472.     for (x = 0; x < endX; x++)
  2473.         {        
  2474.         /* The bits in this column are clear to begin with */
  2475.         tempColumn = 0;
  2476.         
  2477.         /* Which byte to look at in the input buffer */
  2478.         thePtr = basePtr;
  2479.         
  2480.         /*     Where to place the bit in the output. The ImageWriter takes the bit
  2481.             pattern upside down. */
  2482.         outputMask = 0x01;
  2483.         
  2484.         /* Scan through this band, setting each of the 8 bits == the bit in that scan line */
  2485.         for (y = pPackage->startRaster; y < endY; y += incrY)
  2486.             {
  2487.             /* If we have a bit in the input, rotate it into the output */
  2488.             if ((*thePtr) & inputMask)
  2489.                 tempColumn |= outputMask;
  2490.  
  2491.             // move onto next position in the output data                
  2492.             outputMask <<= 1;
  2493.             
  2494.             // move onto the next scan line in the input data
  2495.             thePtr += yPointerOffset;
  2496.             } // for y
  2497.             
  2498.             
  2499.         /* Save the column info */ 
  2500.         pTheScanLine->iTheData[whichCol] = tempColumn;
  2501.         
  2502.         /* Get the next bit from the current pointer */
  2503.         inputMask >>= packingColor;
  2504.         if (!inputMask)
  2505.             {
  2506.             /* If we run out of bits, get the next byte */
  2507.             basePtr++;
  2508.             
  2509.             /* And reset the bit mask to the first bit */
  2510.             inputMask = startingInputMask;
  2511.             }
  2512.             
  2513.         /* If we have some form of data */
  2514.         if (tempColumn != 0)
  2515.             {
  2516.             if (!bandIsDirty)
  2517.                 {
  2518.                 /* This is the first dirty pixels we have so far */
  2519.                 bandIsDirty = true;
  2520.                 firstDirty = x;
  2521.                 }
  2522.             
  2523.             /* This is also the last dirty pixels so far */
  2524.             lastDirty = x;
  2525.             } // SetDirty
  2526.             
  2527.         /* If we have some dirty bits */
  2528.         if (bandIsDirty)
  2529.             {
  2530.             /* Move on to the next column */
  2531.             whichCol++;
  2532.             
  2533.             /* If this is a dirty column, then it is the last one so far */
  2534.             if (tempColumn != 0)
  2535.                 lastDirtyCol = whichCol;
  2536.             
  2537.             /* If we have a duplication, up the repeat count */
  2538.             if (tempColumn == lastColumn) // if (false) // turn off repeat groups
  2539.                 {
  2540.                 repeatCount++;
  2541.                 if (repeatCount == 14)
  2542.                     {
  2543.                     /* Kick out the old group */
  2544.                     whichCol -= 14;
  2545.                         EMITGROUP(pTheScanLine, kGraphicsCommand, whichCol);
  2546.                         numberBytesAdded += whichCol + kGroupSize;
  2547.                         pTheScanLine = (ScanLinePtr)(((Ptr) pTheScanLine) +
  2548.                             whichCol + kGroupSize);
  2549.                     
  2550.                     whichCol = 1;
  2551.                     lastDirtyCol = 1;
  2552.                     pTheScanLine->iTheData[0] = tempColumn;
  2553.                     }
  2554.                 }
  2555.             else
  2556.                 {
  2557.                 /* If we were repeating, emit the repeat group */
  2558.                 if (repeatCount >= 14)
  2559.                     {
  2560.                     EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
  2561.                     numberBytesAdded += 1 + kGroupSize;
  2562.                     pTheScanLine = (ScanLinePtr) (((Ptr) pTheScanLine) + 
  2563.                         1 + kGroupSize);
  2564.                         
  2565.                     whichCol = 1;
  2566.                     lastDirtyCol = 1;
  2567.                     pTheScanLine->iTheData[0] = tempColumn;
  2568.                     }
  2569.                 repeatCount = 0;
  2570.                 lastColumn = tempColumn;
  2571.                 }
  2572.                 
  2573.             } // BandIsDirty
  2574.             
  2575.         } // end of loop for width of bitmap
  2576.  
  2577.     /* if we have a dirty band - emit the final bit of data we have
  2578.        packaged up */
  2579.     if (bandIsDirty)
  2580.         {            
  2581.         
  2582.         /* Set the margins to be the first and last dirty pixels in the scan line -
  2583.            the ImageWriter only does left margin optimization. */
  2584.         {
  2585.             SetMarginsPtr        marginBuffer;
  2586.             SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  2587.             
  2588.             check(hGlobals);
  2589.             
  2590.             /* Get the location for placing the set margin command */
  2591.             marginBuffer = (SetMarginsPtr) (buffer + (*bufferPos));
  2592.             
  2593.             /* Stuff in the set margin command */
  2594.             marginBuffer->cEscape  = ESCAPE;
  2595.             marginBuffer->cCommand = kSetMarginsCommand;
  2596.             
  2597.             /* convert left margin into ASCII and place it at the start of the buffer */
  2598.             Long2Dec((**hGlobals).leftMargin + firstDirty, (Ptr)(marginBuffer->cIndentDistance));
  2599.         }
  2600.         
  2601.         /* Send the last group command */
  2602.         if (repeatCount < 14)
  2603.             {
  2604.             /* Emit a normal group */
  2605.             EMITGROUP(pTheScanLine, kGraphicsCommand, lastDirtyCol);
  2606.             numberBytesAdded += lastDirtyCol + kGroupSize;
  2607.             }
  2608.         else
  2609.             {
  2610.             /* Don't stuff a final repeat group if it's blank space */
  2611.             if (tempColumn != 0)
  2612.                 {
  2613.                 /* Emit a repeat group */
  2614.                 EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
  2615.                 numberBytesAdded += 1 + kGroupSize;
  2616.                 }
  2617.             } // end of repeatCount < 14
  2618.                     
  2619.         
  2620.         /*    Increment the count of the buffer by bytes added for groups, plus
  2621.             the header, if any, plus the set margins command */
  2622.         (*bufferPos) += numberBytesAdded + kScanLineSize + kSetMarginsSize;
  2623.  
  2624.         /* and put a <cr> at the end of the line */
  2625.         *(char*)(buffer + (*bufferPos)) = '\n';
  2626.         (*bufferPos) += 1;
  2627.         
  2628.         } // bandIsDirty
  2629.     else
  2630.         {
  2631.         // don't output data if we didn't have any!
  2632.         *bufferPos = originalBufferPos;
  2633.  
  2634.         // restore original number of line feeds
  2635.         pGlobals = *hGlobals;
  2636.         pGlobals->lineFeeds = originalLineFeeds;
  2637.         } // band is not dirty
  2638.         
  2639.     // always return your errors!
  2640. SendInitialLineFeeds:
  2641.     return(anErr);
  2642.     
  2643. } // SD_PackageBitmap
  2644.  
  2645.  
  2646.  
  2647.  
  2648. // SD_DespoolPage is an override for GXDespoolPage.  In here, we flip the
  2649. // transform of our page shapes, if that's what the user specified in our
  2650. // options dialog.
  2651.  
  2652. OSErr SD_DespoolPage(gxSpoolFile aSpoolFile, long pageNum, gxFormat pageFormat,
  2653.                      gxShape *thePage, Boolean *formatChanged)
  2654. {
  2655.     OSErr                        err;
  2656.     gxFlipPageHorizontalInfo    hFlipInfo;
  2657.     gxFlipPageVerticalInfo        vFlipInfo;
  2658.     long                        itemSize;
  2659.     gxMapping                    pgMapping;
  2660.     gxRectangle                    pageSize, paperSize;
  2661.     char                        flipVar;
  2662.  
  2663. // First, forward the message so that we get the final page shape.
  2664.  
  2665.     err = Forward_GXDespoolPage(aSpoolFile, pageNum, pageFormat, thePage,
  2666.                                 formatChanged);
  2667.  
  2668.     nrequire(err, Despool_Failed);
  2669.  
  2670.  
  2671. // Now, see if the user said to flip the page horizontally or vertically.
  2672. // If the flipping tags arn't present, we'll assume that means "don't flip."
  2673. // If we're not flipping, return from the routine.
  2674.  
  2675.     itemSize = sizeof(gxFlipPageHorizontalInfo);
  2676.         
  2677.     err = GetFmtCollectionItem(&hFlipInfo, &itemSize, gxFlipPageHorizontalTag,
  2678.                                gxPrintingTagID, pageFormat);
  2679.  
  2680.     if (err) hFlipInfo.flipHorizontal = false;
  2681.  
  2682.     itemSize = sizeof(gxFlipPageVerticalInfo);
  2683.     
  2684.     err = GetFmtCollectionItem(&vFlipInfo, &itemSize, gxFlipPageVerticalTag,
  2685.                                gxPrintingTagID, pageFormat);
  2686.  
  2687.     if (err)
  2688.     {
  2689.         vFlipInfo.flipVertical = false;
  2690.         err = noErr;
  2691.     }
  2692.  
  2693.     require((hFlipInfo.flipHorizontal || vFlipInfo.flipVertical), NoFlipping);
  2694.  
  2695.  
  2696. // We store a 1,2, or 3 in flipVar, which allows us to use a switch statement
  2697. // to determine the correct flipping to do.  Next, we get the format's
  2698. // dimensions and the shape's mapping, which will be used to flip the image.
  2699.  
  2700.     flipVar = (char) hFlipInfo.flipHorizontal + 2* (char) vFlipInfo.flipVertical;
  2701.     
  2702.     GXGetFormatDimensions(pageFormat, &pageSize, &paperSize);
  2703.     GXGetShapeMapping(*thePage, &pgMapping);
  2704.  
  2705.  
  2706. // This next part is a little obscure, but if you picture a paperType, we
  2707. // want to translate the origin from one corner of the page to another, and
  2708. // then scale negatively (which does the actual flipping).  For the horizontal
  2709. // flip, we need to move the origin to its horizontally opposite corner, and
  2710. // for a vertical flip, we need to move the origin to its vertically opposite
  2711. // corner.  (This means that horizontal flipping causes the origin to move
  2712. // from the top/left corner to the top/right one, and for vertical flipping
  2713. // it moves to the bottom/left corner.)  If vertical and horizontal flipping
  2714. // are combined, then the two actions are combined.  Note that you need to do
  2715. // the origin translation, since the negative scaling would make your shape
  2716. // live outside of the bounds of the pageArea otherwise, which would cause it
  2717. // to be clipped.
  2718.  
  2719.     switch (flipVar)
  2720.     {
  2721.         case 1:            // horizontal only.
  2722.             MoveMapping(&pgMapping, -paperSize.left -pageSize.right, 0);
  2723.             ScaleMapping(&pgMapping, ff(-1), ff(1), 0, 0);
  2724.             break;
  2725.  
  2726.         case 2:            // vertical only.
  2727.             MoveMapping(&pgMapping, 0, -paperSize.top -pageSize.bottom);
  2728.             ScaleMapping(&pgMapping, ff(1), ff(-1), 0, 0);
  2729.             break;
  2730.  
  2731.         case 3:            // horizontal and vertical.
  2732.             MoveMapping(&pgMapping, -paperSize.left -pageSize.right, -paperSize.top -pageSize.bottom);
  2733.             ScaleMapping(&pgMapping, ff(-1), ff(-1), 0, 0);
  2734.             break;
  2735.     }
  2736.  
  2737. // Finally, set the shape's mapping and return.
  2738.  
  2739.     GXSetShapeMapping(*thePage, &pgMapping);
  2740.  
  2741. NoFlipping:
  2742. Despool_Failed:
  2743.     return err;
  2744. }
  2745.  
  2746.  
  2747. // ToggleControl toggles a control on or off.  It's useful for controls
  2748. // like checkboxes or radio buttons, which can only have a value of 0
  2749. // or 1.  The function takes a "void **" so that we don't have to
  2750. // typecast the handle returned from GetDItem before calling this routine.
  2751.  
  2752. void ToggleControl(void **itemH)
  2753. {
  2754.     short ctlVal = GetCtlValue((ControlHandle) itemH);
  2755.  
  2756.     ctlVal = (ctlVal == 1)? 0: 1;
  2757.     SetCtlValue((ControlHandle) itemH, ctlVal);
  2758. }
  2759.  
  2760.  
  2761.  
  2762. /*******************************************************************
  2763.     SD_HandlePanelEvent is our override for GXHandlePanelEvent. If
  2764.     the event is one of ours, we handle it, otherwise we just
  2765.     forward it down the chain.
  2766.     
  2767. ********************************************************************/
  2768.  
  2769. OSErr SD_HandlePanelEvent(gxPanelInfoRecord *panelInfo)
  2770. {
  2771.     OSErr            err = noErr;
  2772.     GrafPtr            oldPort;
  2773.     DialogPtr        pDlg;
  2774.     short            theItem, itemKind, ctlVal;
  2775.     Rect            itemRect;
  2776.     Handle            itemHdl;
  2777.     
  2778. // Get a pointer to the dialog, save our current grafPort,
  2779. // and set us to the dialog's port.
  2780.  
  2781.     pDlg = panelInfo->pDlg;
  2782.     GetPort(&oldPort);
  2783.     SetPort(pDlg);
  2784.  
  2785.     switch (panelInfo->panelEvt)
  2786.     {
  2787.         case gxPanelOpenEvt:
  2788.                                     // Light up our checkboxes, as appropriate.
  2789.             
  2790.             GetDItem(pDlg, panelInfo->itemCount +d_pHFlip, &itemKind, &itemHdl, &itemRect);
  2791.             ctlVal = (gFlippedPicts->curFlipping & 0x01)? 1:0;
  2792.             SetCtlValue((ControlHandle) itemHdl, ctlVal);
  2793.             GetDItem(pDlg, panelInfo->itemCount +d_pVFlip, &itemKind, &itemHdl, &itemRect);
  2794.             ctlVal = (gFlippedPicts->curFlipping & 0x02)? 1:0;
  2795.             SetCtlValue((ControlHandle) itemHdl, ctlVal);
  2796.         break;
  2797.  
  2798.         case gxPanelHitEvt:
  2799.                                     // If it's a hit in our checkboxes, process.
  2800.  
  2801.             theItem = panelInfo->itemHit -panelInfo->itemCount;
  2802.  
  2803.             if ((theItem == d_pHFlip) || (theItem == d_pVFlip))
  2804.             {
  2805.                 GetDItem(pDlg, panelInfo->itemHit, &itemKind, &itemHdl, &itemRect);
  2806.                 ToggleControl((void **) itemHdl);
  2807.                 gFlippedPicts->curFlipping = GetCurFlip(pDlg, d_pHFlip +panelInfo->itemCount, d_pVFlip +panelInfo->itemCount);
  2808.  
  2809.                 GetDItem(pDlg, panelInfo->itemCount +d_FlipPict,
  2810.                          &itemKind, &itemHdl, &itemRect);
  2811.  
  2812.                 InvalRect(&itemRect);
  2813.             }
  2814.         
  2815.         break;
  2816.     }
  2817.  
  2818. // Restore the original port as we leave.
  2819.  
  2820.     SetPort(oldPort);
  2821.     return err;
  2822. }
  2823.  
  2824.  
  2825. /*******************************************************************
  2826.     SD_FilterPanelEvent is a routine to filter update events in our
  2827.     panel, and update our userItems accordingly.
  2828.  
  2829. ********************************************************************/
  2830.  
  2831. OSErr SD_FilterPanelEvent(gxPanelInfoRecord *panelInfo, Boolean *returnImmed)
  2832. {
  2833.     OSErr        err = noErr;
  2834.     DialogPtr    pDlg;
  2835.  
  2836. #pragma unused(returnImmed);
  2837.  
  2838. // Get a pointer to the dialog, save our current grafPort,
  2839. // and set us to the dialog's port.
  2840.  
  2841.     pDlg = panelInfo->pDlg;
  2842.  
  2843.     switch (panelInfo->panelEvt)
  2844.     {
  2845.         case gxPanelFilterEvt:
  2846.         
  2847.             switch (panelInfo->theEvent->what)
  2848.             {
  2849.                 case updateEvt:        // look for, and handle, our update events.
  2850.  
  2851.                     if ((WindowPtr) panelInfo->theEvent->message == pDlg)
  2852.                         err = HandlePanelUpdate(pDlg, panelInfo);
  2853.  
  2854.                     break;
  2855.             }
  2856.             break;
  2857.     }
  2858.  
  2859.     return err;
  2860. }
  2861.  
  2862.  
  2863. /*******************************************************************
  2864.     HandlePanelUpdate is a routine to update our panel's userItems.
  2865.     Note that we don't pass this routine to the Dialog Manager,
  2866.     we only get here by way of our panel event handler.  This
  2867.     assures that we can access our global data, and that our
  2868.     resource file is open.  In this example, we draw from a global
  2869.     PicHandle, to show that our globals are intact.
  2870.     
  2871.     NOTE: With the exception of the code below that's marked:
  2872.     
  2873.                "YOU SHOULD CHANGE THE FOLLOWING…"
  2874.     
  2875.     you can just use this code verbatim, regardless of the number
  2876.     or purpose of your dialog's userItems.
  2877.     
  2878. ********************************************************************/
  2879.  
  2880. OSErr HandlePanelUpdate(DialogPtr theDialog, gxPanelInfoRecord *panelInfo)
  2881. {
  2882.     GrafPtr        oldPort;
  2883.     OSErr        err;
  2884.     Rect        theClipRect, myUserItemRect;
  2885.     RgnHandle    tempRgn, oldVis;
  2886.     Point        top;
  2887.     short        dx, dy, itemKind;
  2888.     Handle        itemHdl;
  2889.  
  2890. // Create a new region handle.  If we can't do that, return an error.
  2891.  
  2892.     tempRgn = NewRgn();
  2893.     require_action(tempRgn, CanNotCreateRgn, err = MemError(););
  2894.  
  2895.  
  2896. // Copy the window's update region to our temporary region handle,
  2897. // then adjust the region so that it's correctly aligned with our
  2898. // window.  Finally, intersect this region with the window's visRgn.
  2899.  
  2900.     CopyRgn(((DialogPeek) theDialog)->window.updateRgn, tempRgn);
  2901.     top = *(Point *) &(*tempRgn)->rgnBBox.top;
  2902.     GlobalToLocal(&top);
  2903.     dx = (*tempRgn)->rgnBBox.left - top.h;
  2904.     dy = (*tempRgn)->rgnBBox.top - top.v;
  2905.     OffsetRgn(tempRgn, -dx, -dy);
  2906.     SectRgn(theDialog->visRgn, tempRgn, tempRgn);
  2907.  
  2908.     nrequire((err = MemError()), CanNotCopyRgn);
  2909.  
  2910.  
  2911. // Now, get the boundsRect of our userItem and see if
  2912. // any falls within the update area.  If not, don't
  2913. // bother drawing anything.
  2914.  
  2915.     GetDItem(theDialog, panelInfo->itemCount + d_FlipPict, &itemKind,
  2916.              &itemHdl, &myUserItemRect);
  2917.  
  2918.     theClipRect = (*tempRgn)->rgnBBox;
  2919.     
  2920.     if (SectRect(&myUserItemRect, &theClipRect, &theClipRect))
  2921.     {
  2922.  
  2923. // Save the current visRgn, and store our temporary region as the new
  2924. // visRgn.  This is similar to what happens when BeginUpdate is called.
  2925. // When we draw, only pixels that fall in the update area (clipped to
  2926. // the window's clipRgn) will be drawn.  This keeps us from doing
  2927. // unnecessary redrawing, which would cause flashing and wasted cycles.
  2928.  
  2929.         oldVis = theDialog->visRgn;
  2930.         theDialog->visRgn = tempRgn;
  2931.  
  2932.  
  2933. // Save the current port, change it to the dialog's port, draw any
  2934. // userItems that need updating, validate their areas and restore
  2935. // the old visRgn and grafPort.
  2936.  
  2937.         GetPort(&oldPort);
  2938.         SetPort(theDialog);
  2939.  
  2940. //        Draw picture like old code.
  2941.  
  2942.         DrawPicture(gFlippedPicts->pict[gFlippedPicts->curFlipping], &myUserItemRect);
  2943.         InsetRect(&myUserItemRect, -1, -1);
  2944.         FrameRect(&myUserItemRect);
  2945.         ValidRect(&myUserItemRect);
  2946.                 
  2947.         theDialog->visRgn = oldVis;
  2948.         SetPort(oldPort);
  2949.     }
  2950.  
  2951. // Throw away our temporary region, and return any error.
  2952.  
  2953. CanNotCopyRgn:
  2954.     DisposeRgn(tempRgn);
  2955.  
  2956. CanNotCreateRgn:
  2957.     return err;
  2958. }
  2959.